0

我想确定在 Python 3 脚本中使用 OpenCV 最能代表图像的 2 个色调值。到目前为止,我已经能够访问色调通道并显示其色调直方图: 在此处输入图像描述

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

我已获得对色调通道的访问权限,如下所示:

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

在色调通道上操作以确定哪两个色调值最能代表图像的最有效方法是什么?

编辑 #1 请求的原始图像: 在此处输入图像描述

编辑#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 脚本转换为 2 种颜色需要 8.6 秒。在 Gimp 中转换为 2 种颜色几乎是瞬时的(我知道它是不同的处理器,但 Pi Zero 上的 8.6 秒对我来说是不可用的,也许 1 秒就可以了)。我只是一个新手,但对我来说,当我只想对 Hue 进行操作时,看起来这个 kmeans 代码正在对所有 RGB 像素起作用,所以我不能让 kmeans 仅对 Hue 进行操作并大大缩短时间(这样做有点超出我在这一点上的能力)。

这是需要 8.6 秒的 3.JPG 图像: 在此处输入图像描述

4

1 回答 1

0

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

  1. 您不需要转换回 uint8。Center 是一个大小为 (2,3) 的数组,其中行是您的中心点(ei 色调),列是每个色调的 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。我可以尝试一下,但我不确定您正在使用哪些其他代码以及它是否可以工作。如果你想走这条路,请告诉我。

于 2018-07-05T04:47:16.100 回答