使用python检测图片上的色彩

面对一张色彩绚丽的图片,你很像知道某一块的颜色是什么,这包括色彩的名字和这一点上色彩的RGB值,但在缺少专业工具的情况下,这似乎是一个难以完成的任务,但python可以为我们提供这样的功能,解决pandas, cv2库,我们可以实现这样的功能,最终的效果如下图所示

鼠标双击在红色区域,图片上方则显示出这个区域的颜色信息。那么,该如何实现这样有趣的功能呢?通过本文,你将会学习到cv2库的一般使用方法,例如显示图片,处理鼠标双击事件,在图片上添加文字。

1. 安装必要的python库

pip install opencv-python numpy pandas

opencv是一个强大的图像处理和计算机视觉库, pandas是一种基于numpy的工具,在数据分析方面非常受欢迎,实现图片颜色检测的功能,必须用到这三个库

2. 通过点击获得像素信息

程序需要将图片显示出来,鼠标双击后,程序获得鼠标点击的位置,通过这个位置,获取这个点的像素色彩信息,也就是RGB值。

import cv2

img = cv2.imread('colorpic.jpg')


def click_info(event, x, y, flags, param):
    # 只处理双击事件
    if event == cv2.EVENT_LBUTTONDBLCLK:
        print('坐标', x, y)
        b, g, r = img[y, x]     # 获取b, g, r
        print("像素点的bgr值", b, g, r)

cv2.namedWindow('image')
cv2.setMouseCallback('image',  click_info)

while True:
    cv2.imshow("image", img)
    # 点击 esc键
    if cv2.waitKey(20) & 0xFF ==27:
        break

cv2.destroyAllWindows()

执行程序,双击图片上的某一点,就可以获得鼠标所点击区域的x,y值

3. 在图片上显示文字

为了在图片上显示文字,先使用rectangle方法绘制出一个矩形区域,需要指定矩形的左上角和右下角的x,y 值,并指定色彩,下面的示例中,色彩我选择了(0, 0, 0) 黑色。putText方法用于显示文字,指定文字开始的x, y坐标

import cv2

img = cv2.imread('colorpic.jpg')
cv2.rectangle(img, (20, 20), (750, 60), (0,0,0), -1)
cv2.putText(img, 'this is a picture', (50,50), 2, 0.8, (255,255,255), 2, cv2.LINE_AA)

while True:
    cv2.imshow("image", img)
    # 点击 esc键
    if cv2.waitKey(20) & 0xFF ==27:
        break

cv2.destroyAllWindows()

4. 根据RGB值计算色彩名称

RGB色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是运用最广的颜色系统之一。前面已经讲解如何获得像素点的RGB, 那么如何通过这三个值判断它属于哪种颜色呢?

首先,需要一份颜色信息表,记录色彩的名称和RGB值,这些信息记录在一份csv文件中,格式如下

air_force_blue_raf,"Air Force Blue (Raf)",#5d8aa8,93,138,168
air_force_blue_usaf,"Air Force Blue (Usaf)",#00308f,0,48,143
air_superiority_blue,"Air Superiority Blue",#72a0c1,114,160,193

第二列是色彩名称,后散列是RGB值,使用pandas将数据读取到dataframe中,获得一个像素点后,计算遍历dataframe中的所有数据,找到r, g, b差值最小的那一个就可以任务是该颜色

import pandas as pd

index = ["color", "color_name", "hex", "R", "G", "B"]
csv_df = pd.read_csv('colors.csv', names=index, header=None)


def get_color_name(r, g, b):
    min_diff = 10000
    color_name = ''
    for i in range(len(csv_df)):
        d = abs(r- int(csv_df.loc[i,"R"])) + abs(g- int(csv_df.loc[i,"G"]))+ abs(b- int(csv_df.loc[i,"B"]))
        if d <= min_diff:
            min_diff = d
            color_name = csv_df.loc[i,"color_name"]
    return color_name

函数get_color_name根据r, g, b的值来确定色彩名称

5.全部代码

import pandas as pd
import cv2


def get_color_name(r, g, b):
    min_diff = 10000
    color_name = ''
    for i in range(len(csv_df)):
        d = abs(r - int(csv_df.loc[i, "R"])) + abs(g - int(csv_df.loc[i, "G"]))+ abs(b - int(csv_df.loc[i, "B"]))
        if d <= min_diff:
            min_diff = d
            color_name = csv_df.loc[i,"color_name"]
    return color_name


def click_info(event, x, y, flags, param):
    # 只处理双击事件
    if event == cv2.EVENT_LBUTTONDBLCLK:
        global b,g,r,xpos,ypos, clicked
        xpos = x
        ypos = y
        b, g, r = img[y, x]     # 获取b, g, r
        b = int(b)
        g = int(g)
        r = int(r)
        clicked = True

r = g = b = xpos = ypos = 0
clicked = False
img = cv2.imread('colorpic.jpg')
index = ["color", "color_name", "hex", "R", "G", "B"]
csv_df = pd.read_csv('colors.csv', names=index, header=None)

cv2.namedWindow('image')
cv2.setMouseCallback('image',  click_info)

while True:
    cv2.imshow("image", img)
    if clicked:
        # 绘制显示文字的区域
        cv2.rectangle(img, (20, 20), (750, 60), (b, g, r), -1)
        text = get_color_name(r, g, b) + ' R='+ str(r) +  ' G='+ str(g) + ' B='+ str(b)
        # 显示文字内容
        cv2.putText(img, text, (50, 50), 2, 0.8, (255, 255, 255), 2, cv2.LINE_AA)

        # 如果像素点的颜色太偏向于白色,就用黑色来显示文字
        if(r + g + b >= 600):
            cv2.putText(img, text, (50, 50), 2, 0.8, (0, 0, 0), 2, cv2.LINE_AA)

    clicked=False
    # 点击 esc键
    if cv2.waitKey(20) & 0xFF ==27:
        break

cv2.destroyAllWindows()

6. 获取源码及数据

想要获取程序所用图片及colors.csv文件,扫描关注微信公众号并回复 色彩 ,即可获得图片与文件,包括源码

扫描关注, 与我技术互动

QQ交流群: 211426309

加入知识星球, 每天收获更多精彩内容

分享日常研究的python技术和遇到的问题及解决方案