OpenCV确定哪两个色相值最能代表图像

时间:2018-07-04 14:54:44

标签: python opencv

我想确定在Python 3脚本中使用OpenCV哪种2色相值最能代表一幅图像。 到目前为止,我已经能够访问色相通道并显示其色相直方图: enter image description here

如您所见,基本上有两种不同色调的像素,米色和绿色。

我已按如下方式访问色相频道:

hsv = cv.cvtColor( self.img, cv.COLOR_BGR2HSV )
hue,sat,val = cv.split(hsv)

在色调通道上进行操作以确定最适合表示图像的两个色调值的最有效方法是什么?

请求编辑#1原始图像: enter image description here

编辑#2快到了,但仍然需要帮助:

我整理了一些代码,以使用OpenCV kmeans将图像转换为2种颜色:

import numpy as np
import cv2
import time
import sys

img = cv2.imread('3.JPG')
cv2.imshow('Original',img)
print (sys.version)
if sys.version_info[0] < 3:
    raise Exception("Python 3 or a more recent version is required.")

def redo():
    Z = img.reshape((-1,3))
    # convert to np.float32
    Z = np.float32(Z)
    # define criteria, number of clusters(K) and apply kmeans()
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
    K = 2
    start_time = time.time()
    ret,label,center=cv2.kmeans(Z,K,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)
    end_time = time.time()
    print("Elapsed time was %g seconds" % (end_time - start_time))
    # Now convert back into uint8, and make original image
    center = np.uint8(center)
    res = center[label.flatten()]
    res2 = res.reshape((img.shape))
    cv2.imshow('Converted',res2)    

while(1):
    ch = cv2.waitKey(50)
    if ch == 27:
        break
    if ch == ord(' '):
        redo()
        
cv2.destroyAllWindows()

仍需要:

  1. 我真的不想转换回uint8并将原始图像制成2种颜色。我想知道这两种颜色的色相值。如何从kmeans输出参数中获得这两个值?
  2. 有没有办法减少使用kmeans转换的时间? kmeans在我的Raspberry Pi Zero上使用Python 3脚本需要8.6秒才能转换为2种颜色。在Gimp中转换为2种颜色几乎是瞬时的(我知道它是不同的处理器,但是在Pi Zero上8.6秒对于我来说是不可用的,也许1秒就可以了)。我只是一个新手,但对我来说,当我只希望对Hue进行操作时,此kmeans代码似乎对所有RGB像素都起作用,所以我不能让kmeans仅对Hue进行操作并大大节省时间(这样做有点超出我的能力到此为止。

这是耗时8.6秒的3.JPG图像: enter image description here

1 个答案:

答案 0 :(得分:0)

我已经解决了您在帖子中提到的一些事情。

  1. 您不需要回退到uint8。中心是大小为(2,3)的数组,其中行是您的中心点(例如色相),列是每种色相的BGR值。

  2. 我已切换到Scipy KMeans2,而不是使用OpenCVs实现。在与OpenCV相同的图像上,速度似乎要快3倍。

    import numpy as np
    from scipy.cluster.vq import kmeans, kmeans2
    import time, sys, cv2
    
    img = cv2.imread('3.jpg')                                                                                                                              
    print (sys.version)                                                                                                                                    
    if sys.version_info[0] < 3:
        raise Exception("Python 3 or a more recent version is required.")
    
    def redo():                                                                                                                                            
        Z = img.reshape((-1,3))                                                                                                                            
        Z = np.float32(Z)                                                                                                 
    
        # define criteria, number of clusters(K) and apply kmeans()                                                                                        
        criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)                                                                           
        K = 2                                                                                                                                              
        start_time = time.time()                                                                                                                           
        ret,label,center=cv2.kmeans(Z,K,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)                                                                        
        end_time = time.time()                                                                                                                             
        print("Elapsed cv2 time was %g seconds" % (end_time - start_time))                                                                                 
        print("center")                                                                                                                                    
        print(center)                                                                                                                                      
    
        start_time = time.time()                                                                                                                           
        spcenter, splabel = kmeans2(Z,K,10,1,'points','warn',False)                                                                                        
        end_time = time.time()                                                                                                                             
        print("Elapsed scipy time was %g seconds" % (end_time - start_time))                                                                               
        print("center")                                                                                                                                    
        print(spcenter)                                                                                                                                    
    
        print("diff")                                                                                                                                      
        check = np.abs(spcenter[0][0]-center[0][0])                                                                                                        
        checkflip = np.abs(spcenter[0][0]-center[1][0])                                                                                                    
        if (check < checkflip):                                                                                                                            
            print(np.abs(spcenter-center))                                                                                                                 
        else:                                                                                                                                              
            print("labels are flipped, has no effect on data")                                                                                             
            print(np.abs(spcenter-np.roll(center,1,0)))                                                                                                    
    
        # Now convert back into uint8, and make original image                                                                                             
        #center = np.uint8(center)                                                                                                                         
        res = spcenter[splabel.flatten()]
        res2 = res.reshape((img.shape))                                                                                                                    
        cv2.imwrite('converted.jpg',res2)                                                                                                                  
    
    redo()
    

您可能无法比此代码给您提供任何计时都更好。如果可以解决问题,则可以尝试缩小图像。这样可以加快处理速度。

另一个解决方案,如我提到的,正在转向一种更快的语言,例如C。我可以尝试一下,但是我不确定您正在使用什么其他代码以及它是否可以工作。让我知道您是否想走这条路。