Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在OpenCV中提取具有特定颜色的图像片段?_Python_Numpy_Opencv_Image Processing - Fatal编程技术网

Python 如何在OpenCV中提取具有特定颜色的图像片段?

Python 如何在OpenCV中提取具有特定颜色的图像片段?,python,numpy,opencv,image-processing,Python,Numpy,Opencv,Image Processing,我使用徽标和其他简单的图形,其中没有渐变或复杂的图案。我的任务是从带有字母和其他元素的徽标片段中提取 为了做到这一点,我定义了背景颜色,然后我通过图片来分割图像。以下是我的代码,以便于进一步理解: MAXIMUM_COLOR_TRANSITION_DELTA = 100 # 0 - 765 def expand_segment_recursive(image, unexplored_foreground, segment, point, color): height, width

我使用徽标和其他简单的图形,其中没有渐变或复杂的图案。我的任务是从带有字母和其他元素的徽标片段中提取

为了做到这一点,我定义了背景颜色,然后我通过图片来分割图像。以下是我的代码,以便于进一步理解:

MAXIMUM_COLOR_TRANSITION_DELTA = 100  # 0 - 765


def expand_segment_recursive(image, unexplored_foreground, segment, point, color):
    height, width, _ = image.shape
    # Unpack coordinates from point
    py, px = point

    # Create list of pixels to check
    neighbourhood_pixels = [(py, px + 1), (py, px - 1), (py + 1, px), (py - 1, px)]

    allowed_zone = unexplored_foreground & np.invert(segment)

    for y, x in neighbourhood_pixels:
        # Add pixel to segment if its coordinates within the image shape and its color differs from segment color no
        # more than MAXIMUM_COLOR_TRANSITION_DELTA
        if y in range(height) and x in range(width) and allowed_zone[y, x]:
            color_delta = np.sum(np.abs(image[y, x].astype(np.int) - color.astype(np.int)))
            print(color_delta)
            if color_delta <= MAXIMUM_COLOR_TRANSITION_DELTA:
                segment[y, x] = True
                segment = expand_segment_recursive(image, unexplored_foreground, segment, (y, x), color)
                allowed_zone = unexplored_foreground & np.invert(segment)

    return segment


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Pass image as the argument to use the tool")
        exit(-1)

    IMAGE_FILENAME = sys.argv[1]
    print(IMAGE_FILENAME)

    image = cv.imread(IMAGE_FILENAME)
    height, width, _ = image.shape

    # To filter the background I use median value of the image, as background in most cases takes > 50% of image area.
    background_color = np.median(image, axis=(0, 1))
    print("Background color: ", background_color)

    # Create foreground mask to find segments in it (TODO: Optimize this part)
    foreground = np.zeros(shape=(height, width, 1), dtype=np.bool)
    for y in range(height):
        for x in range(width):
            if not np.array_equal(image[y, x], background_color):
                foreground[y, x] = True

    unexplored_foreground = foreground

    for y in range(height):
        for x in range(width):
            if unexplored_foreground[y, x]:
                segment = np.zeros(foreground.shape, foreground.dtype)
                segment[y, x] = True
                segment = expand_segment_recursive(image, unexplored_foreground, segment, (y, x), image[y, x])

                cv.imshow("segment", segment.astype(np.uint8) * 255)

                while cv.waitKey(0) != 27:
                    continue
MAXIMUM_COLOR_TRANSITION_DELTA=100#0-765
def expand_segment_recursive(图像、未探测的_前景、段、点、颜色):
高度、宽度,u=image.shape
#从点解包坐标
py,px=点
#创建要检查的像素列表
邻域像素=[(py,px+1),(py,px-1),(py+1,px),(py-1,px)]
允许的\u区域=未勘探的\u前景和np.反转(段)
对于y,x邻域像素:
#如果像素在图像形状中的坐标及其颜色不同于段颜色编号,则向段添加像素
#超过最大值\u颜色\u过渡\u增量
如果y在范围(高度)内,x在范围(宽度)内,且允许_区[y,x]:
color_delta=np.sum(np.abs(图像[y,x].astype(np.int)-color.astype(np.int)))
打印(颜色增量)
如果颜色增量为图像面积的50%。
背景颜色=np.中间值(图像,轴=(0,1))
打印(“背景色:”,背景色)
#创建前景遮罩以查找其中的分段(TODO:优化此部分)
前景=np.zero(形状=(高度,宽度,1),数据类型=np.bool)
对于范围内的y(高度):
对于范围内的x(宽度):
如果不是np.数组(图像[y,x],背景色):
前景[y,x]=真
未勘探的前景=前景
对于范围内的y(高度):
对于范围内的x(宽度):
如果未探测到前景[y,x]:
段=np.0(前台.shape,前台.dtype)
段[y,x]=真
分段=展开分段递归(图像、未探索的前景、分段(y,x)、图像[y,x])
cv.imshow(“段”,段.aType(np.uint8)*255)
而cv.waitKey(0)!=27:
持续
以下是期望的结果:

在运行时结束时,我预计将提取13个分离的片段(对于此特定图像)。但是我得到了RecursionError:超过了最大递归深度,这并不奇怪,因为可以为图像的每个像素调用expand_segment_recursive()。因为即使使用600x500的小图像分辨率,我最多也能接到300K的电话

我的问题是,在这种情况下,如何摆脱递归,并可能使用Numpy或OpenCV算法优化算法?

您可以实际使用图像(二进制)并通过几个步骤完成这项工作。此外,您可以使用或其他方法

代码如下:

import numpy as np
import cv2

# load image as greyscale
img = cv2.imread("hp.png", 0)

# puts 0 to the white (background) and 255 in other places (greyscale value < 250)
_, thresholded = cv2.threshold(img, 250, 255, cv2.THRESH_BINARY_INV)

# gets the labels and the amount of labels, label 0 is the background
amount, labels = cv2.connectedComponents(thresholded)

# lets draw it for visualization purposes
preview = np.zeros((img.shape[0], img.shape[2], 3), dtype=np.uint8)

print (amount) #should be 3 -> two components + background

# draw label 1 blue and label 2 green
preview[labels == 1] = (255, 0, 0)
preview[labels == 2] = (0, 255, 0)

cv2.imshow("frame", preview)
cv2.waitKey(0)
结果是:


也许您可以提供另一个示例,另外,请提供您希望作为“结果”获得的结果?哇,循环/递归看起来是个坏主意。您可以尝试进行二值化(阈值),然后连接组件?或者,如果它像这个标志可能会转换为HSV颜色空间,并在范围内选择蓝色部分?在这种特殊情况下,您甚至可以只做一个阈值来获得“蓝色”的遮罩part@api55关键是我们有几个相同颜色的片段。如果我对图像应用阈值,我将在一张图像中获得该颜色的所有片段。这不合适,在这种情况下,段必须分开。连接的组件看起来很相关,你有一个使用它的好例子吗?啊,好的,现在它是有意义的,但是先设置阈值,然后连接组件就可以了。给我一分钟,我写下来作为答案。这个问题可能也很有用:使用
cv::inRange
(OpenCV)选择正确的HSV上下边界进行颜色检测谢谢,@api55作为示例。它为我解释了一个解决方案。由于图像上可能有不同颜色的片段(刚刚意识到此示例并没有涵盖任务的所有边缘情况),我将对每种颜色的几个inRange()矩阵执行connectedComponents()。您应该为我放置一个具有更多颜色的示例图像,以便更好地帮助您。。。连接的组件有时很昂贵,所以在大图像中多次连接可能需要几秒钟的时间来处理。。。也许另一种方法更好。。。。您也可以尝试分水岭算法。现在你可以看到图像实际上可以有不同颜色的片段,并且每个片段都必须被提取出来。@Ruslan有时候,当新问题不同并且答案被接受时,最好打开一个新问题。无论如何,我更新了我的答案以匹配新的标志。。。它不像以前那么干净,因为徽标的彩色部分周围有一些非纯白色
import numpy as np
import cv2

img = cv2.imread("total.png", 0)

# background to black
img[img>=200] = 0
# get edges
canny = cv2.Canny(img, 60, 180)
# make them thicker
kernel = np.ones((3,3),np.uint8)
canny = cv2.morphologyEx(canny, cv2.MORPH_DILATE, kernel)
# apply edges as border in the image
img[canny==255] = 0

# same as before
amount, labels = cv2.connectedComponents(img)
preview = np.zeros((img.shape[0], img.shape[1], 3), dtype=np.uint8)
print (amount) #should be 14 -> 13 components + background

# color them randomly
for i in range(1, amount):
  preview[labels == i] = np.random.randint(0,255, size=3, dtype=np.uint8)

cv2.imshow("frame", preview )
cv2.waitKey(0)