基于openCV-python:HSI颜色空间与H-S直方图比较

目录

RGB/HSI颜色空间解读

直方图概念

基于opencv-python绘制RGB直方图

绘制opencv-python绘制H-S直方图

直方图比较方法

python中其他绘制2D直方图方法

显示直方图

参考资料:


RGB/HSI颜色空间解读

一般用的都是RGB图像。但是由于HSI颜色空间更符合人体感知,因此很多工作都需要先将RGB转为HSI。在冈萨瓦斯的《数字图像处理》中是这样支持使用HSI空间的:

基于openCV-python:HSI颜色空间与H-S直方图比较_第1张图片

也就是说,由于H,S对于光强的鲁棒性,它们是我们重点关注的两个量。在易受光强变化影响的场景下,使用HSI空间是比较可靠的。具体的转换公式:

基于openCV-python:HSI颜色空间与H-S直方图比较_第2张图片

小写是表示归一化的状态。即未拉伸扩充。(常用的是把归一化的h,s,i值做扩充便于理解。见下面程序。)

由于opencv中没有自带转HSI的函数(有转HSV空间的,但是和HSI还有有些差别)。故自行用python实现颜色空间转换:

import numpy as np
import math

def rgb2hsi(img_rgb):
    rows = int(img_rgb.shape[0])
    cols = int(img_rgb.shape[1])
    B, G, R = cv2.split(img_rgb)
    # 归一化到[0,1]
    B = B / 255.0
    G = G / 255.0
    R = R / 255.0
    img_hsi = img_rgb.copy()
    H, S, I = cv2.split(img_hsi)
    for i in range(rows):
        for j in range(cols):
            num = 0.5 * ((R[i, j] - G[i, j]) + (R[i, j] - B[i, j]))
            den = np.sqrt((R[i, j] - G[i, j]) ** 2 + (R[i, j] - B[i, j]) * (G[i, j] - B[i, j]))
            theta = float(np.arccos(num / den))
 
            if den == 0:
                H = 0
            elif B[i, j] <= G[i, j]:
                H = theta
            else:
                H = 2 * np.pi - theta
 
            min_RGB = min(min(B[i, j], G[i, j]), R[i, j])
            sum = B[i, j] + G[i, j] + R[i, j]
            if sum == 0:
                S = 0
            else:
                S = 1 - 3 * min_RGB / sum
 
            H = H / (2 * np.pi)
            I = sum / 3.0
            
            
            # 为了便于理解,常常对结果做扩充,即 [0°,360°],[0,100],[0,255]
#            img_hsi[i, j, 0] = H * 360
#            img_hsi[i, j, 1] = S * 100
#            img_hsi[i, j, 2] = I * 255
            
            # 或者为了便于计算直方图,都扩充为0~255(同RGB)
            img_hsi[i, j, 0] = H * 255
            img_hsi[i, j, 1] = S * 255
            img_hsi[i, j, 2] = I * 255
    return img_hsi

需要注意的是H、S、I三个取值的值域。

但是,opencv官网中给出一个绘制H-S直方图的案例,其中直接调用了BGR2HSV自带方法,即把RGB转成HSV空间了。虽然有点不同,但是H和S的概念还是相同的。如果想在HSI空间下考察图像的颜色特征,其实不必大费周章自己把RGB转成HSI,因为真正有用的信息只是H和S两个分量,所以V和I的定义不一致也就罢了。这样一来,我们直接使用OpenCV中提供的方法就可以快速获得H-S直方图。

直方图概念

直方图是学数字图像的人必须掌握的基础。如果你还不懂其概念,建议先自行百度一下,或查阅数字图像处理相关书籍。简单直白地说,直方图是一种像素值分布的概率模型,比如一张灰度图像,像素值0~255,直方图就可以告诉我们像素值为0的点有几个,为1的有几个,为2的有多少个……但是这样太复杂了,运算量太大,因此引入“灰度级”概念,比如0~16的都算作第一级,16~32的都算作第二级……这样横轴只需要16个刻度值就可以表达完整个图像的灰度情况。

那么既然灰度值可以做直方图(一维),那么二维、三维的当然也可以做,原理是一样的。比如可以把R,G,B三个分量分别提取做来做直方图,就可以得到一张图上3条曲线。

还有一些重要概念,比如直方图均衡化。请自行查阅资料了解一下。

本文讨论如何绘制多维直方图(颜色直方图)。

基于opencv-python绘制RGB直方图

自己编写的程序:

import cv2
import numpy as np
class Hisogram(object):
    
    def create_rgb_hist(self,image,color_type=1):
        """
        获取彩色空间直方图
        """
        h, w, c = image.shape
        rgHist = np.zeros([16*16*16, 1], np.float32)  #必须是float型
        print(rgHist)
        hsize = 256/16
        for row in range (0, h, 1):
            for col in range (0, w, 1):
                b = image[row, col, 0] 
                g = image[row, col, 1] 
                r = image[row, col, 2] 
                index = np.int(b/hsize)*16*16 + np.int(g/hsize)*16 + np.int(r/hsize)
                rgHist[np.int(index), 0] = rgHist[np.int(index), 0] + 1
        return rgHist
     
    def hist_compare(self,image1, image2):
        """
        比较两个直方图
        """
        hist1 = self.create_rgb_hist(image1)
        hist2 = self.create_rgb_hist(image2)
        match1 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_BHATTACHARYYA)
        match2 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CORREL)
        match3 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CHISQR)
        match4 = cv2.compareHist(hist1,hist2 ,cv2.HISTCMP_INTERSECT)
        print("巴氏距离:%s,相关性:%s,卡方:%s,HISTCMP_INTERSECT:%s " % (match1, match2, match3,match4))
     
    def hist_image(self,image):
        color = ("Hue", "Saturity", "Intensity")
        for i, color in enumerate(color):
            hist = cv2.calcHist([image], [i], None, [256], [0, 256])  #计算rgb的直方图
#            hist = cv.calcHist([image], [0,1], None, [180,256], [0,180,0,256])  #计算H-S直方图
        print(hist)
 
if __name__ == '__main__':
    image1 = cv2.imread("shuibo1/2.jpg")[190:220,220:250,:]
    image2 = cv2.imread("shuibo1/2.jpg")[190:220,250:280,:]
    #hist_image(image1)
    myHist=Hisogram()
    myHist.hist_compare(image1, image2)

绘制opencv-python绘制H-S直方图

此处可以直接借助opencv官网给的案例:非常容易实现!

import numpy as np
import cv2 as cv
img = cv.imread('home.jpg')
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
hist = cv.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])

calcHist是得到直方图的函数:

images是原始图像,需要使用[]修饰;cv2.calcHist()函数一次只能得到一张图片的其中一个通道的直方图,所以,channels传入的是本次需要处理的元素图片的通道的索引号,同样需要使用[]修饰。如果输入的元素图像是灰度图,它的值就是[0]; 如果输入的元素图像是彩色图像的话,传入的参数可以是[0], [1], [2],它们分别对应着通道B, G, R。

直方图比较方法

画好了直方图后,我们往往希望借助直方图比较两幅图像的颜色相似程度。即颜色直方图可以用来作为颜色特征来比较。那么利用直方图来比较的方法有哪些呢?

调用方法:(我们在第二节“基于opencv-python绘制RGB直方图”的程序中也已经使用了这个方法,可参考如何使用)

opencv中自带的方法有:

基于openCV-python:HSI颜色空间与H-S直方图比较_第3张图片

具体含义:

基于openCV-python:HSI颜色空间与H-S直方图比较_第4张图片

 

python中其他绘制2D直方图方法

python的numpy模块也提供了2D直方图的绘制方法。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('home.jpg')
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
hist, xbins, ybins = np.histogram2d(h.ravel(),s.ravel(),[180,256],[[0,180],[0,256]])

显示直方图

方法1:cv.imshow()

方法2:使用Matplotlib:

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('home.jpg')
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
hist = cv.calcHist( [hsv], [0, 1], None, [180, 256], [0, 180, 0, 256] )
plt.imshow(hist,interpolation = 'nearest')
plt.show()

基于openCV-python:HSI颜色空间与H-S直方图比较_第5张图片

参考资料:

2D直方图,opencv官方教程:https://docs.opencv.org/3.4.0/dd/d0d/tutorial_py_2d_histogram.html

以及它的中文翻译by网友:https://blog.csdn.net/JS_XH/article/details/79270584

直方图函数的详解:https://www.cnblogs.com/aobosir/p/5928676.html(排版不是很好…)

颜色空间转换的python代码:https://blog.csdn.net/qq_38328871/article/details/85060459

 

你可能感兴趣的:(机器视觉/计算机视觉,Python)