【问题标题】:Region Growing python区域生长的蟒蛇
【发布时间】:2021-05-11 15:21:21
【问题描述】:

我致力于在 python 中实现区域增长算法。但是当我在输出上运行此代码时,我得到没有错误的黑色图像。在输入图像上使用 CV 阈值函数,对于种子值,我使用鼠标单击将 x,y 值存储在元组中。

def get8n(x, y, shape):
    out = []
    if y-1 > 0 and x-1 > 0:
        out.append( (y-1, x-1) )
    if y-1 > 0 :
        out.append( (y-1, x))
    if y-1 > 0 and x+1 < shape[1]:
        out.append( (y-1, x+1))
    if x-1 > 0:
        out.append( (y, x-1))
    if x+1 < shape[1]:
        out.append( (y, x+1))
    if y+1 < shape[0] and x-1 > 0:
        out.append( ( y+1, x-1))
    if y+1 < shape[0] :
        out.append( (y+1, x))
    if y+1 < shape[0] and x+1 < shape[1]:
       out.append( (y+1, x+1))
    return out

def region_growing(img, seed):
    list = []
    outimg = np.zeros_like(img)

    list.append((seed[0], seed[1]))
    while(len(list)):
        pix = list[0]
        outimg[pix[0], pix[1]] = 255
        for coord in get8n(pix[0], pix[1], img.shape):
            if img[coord[0], coord[1]] > 0:
                outimg[coord[0], coord[1]] = 255
                list.append((coord[0], coord[1]))
        list.pop(0)
    return outimg

def on_mouse(event, x, y, flags, params): 
    if event == cv2.EVENT_LBUTTONDOWN: 
        print 'Seed: ' + str(x) + ', ' + str(y) 
        clicks.append((y,x)) 

clicks = []
image = cv2.imread('lena.jpg', 0) 
ret, img = cv2.threshold(image, 200, 255, cv2.THRESH_BINARY) 
cv2.namedWindow('Input') 
cv2.setMouseCallback('Input', on_mouse, 0, ) 
cv2.imshow('Input', img) 
cv2.waitKey() 
seed = clicks[-1] 
cv2.imshow('Region Growing', region_growing(img, seed)) 
cv2.waitKey() 
cv2.destroyAllWindows()

【问题讨论】:

  • 既然您询问的是读取和显示图像,您能否包含读取/操作输入图像和显示输出图像的代码?
  • 输入图片有全部代码def on_mouse(event, x, y, flags, params): if event == cv2.EVENT_LBUTTONDOWN: print 'Seed: ' + str(x) + ', ' + str(y) clicks.append((y,x)) clicks = [] image = cv2.imread('lenna.jpg', 0) ret, img = cv2.threshold(image, 200, 255, cv2.THRESH_BINARY) cv2.namedWindow('Input') cv2.setMouseCallback('Input', on_mouse, 0, ) cv2.imshow('Input', img) cv2.waitKey() seed = clicks[-1] cv2.imshow('Region Growing', region_growing(img, seed)) cv2.waitKey() cv2.destroyAllWindows()
  • 将代码添加到问题中,格式正确 - 这样不可读。
  • 你希望你的代码做什么?现在,它似乎在您最后单击的位置绘制了一个带有白色像素的空白图像。如果单击输入的白色区域,它将进入无限循环。另一方面,这意味着输出图像不是黑色的,而是有一个白色像素。
  • 我想通过种子像素(点击)的所有相邻像素和值大于0的像素设置为255。只要有大于0的相邻像素就继续。并分配它们到将成为输出图像的区域

标签: python opencv


【解决方案1】:

我在使用您的 get8n() 函数时遇到了一些问题,所以我重写了它。我相信下面的代码可以满足您的要求。 region_growth() 函数中有两行被注释掉。如果您取消注释它们,它们将显示处理过程中发生的事情的动画。这是一种可视化代码并让您了解问题所在的好方法。

此外,在您的代码中,您可以将已处理的像素添加到“待处理”列表中。这导致了无限循环。我添加了一项检查,以防止已处理的像素重新添加到列表中。

import cv2
import numpy as np

def get8n(x, y, shape):
    out = []
    maxx = shape[1]-1
    maxy = shape[0]-1
    
    #top left
    outx = min(max(x-1,0),maxx)
    outy = min(max(y-1,0),maxy)
    out.append((outx,outy))
    
    #top center
    outx = x
    outy = min(max(y-1,0),maxy)
    out.append((outx,outy))
    
    #top right
    outx = min(max(x+1,0),maxx)
    outy = min(max(y-1,0),maxy)
    out.append((outx,outy))
    
    #left
    outx = min(max(x-1,0),maxx)
    outy = y
    out.append((outx,outy))
    
    #right
    outx = min(max(x+1,0),maxx)
    outy = y
    out.append((outx,outy))
    
    #bottom left
    outx = min(max(x-1,0),maxx)
    outy = min(max(y+1,0),maxy)
    out.append((outx,outy))
    
    #bottom center
    outx = x
    outy = min(max(y+1,0),maxy)
    out.append((outx,outy))
    
    #bottom right
    outx = min(max(x+1,0),maxx)
    outy = min(max(y+1,0),maxy)
    out.append((outx,outy))
    
    return out

def region_growing(img, seed):
    seed_points = []
    outimg = np.zeros_like(img)
    seed_points.append((seed[0], seed[1]))
    processed = []
    while(len(seed_points) > 0):
        pix = seed_points[0]
        outimg[pix[0], pix[1]] = 255
        for coord in get8n(pix[0], pix[1], img.shape):
            if img[coord[0], coord[1]] != 0:
                outimg[coord[0], coord[1]] = 255
                if not coord in processed:
                    seed_points.append(coord)
                processed.append(coord)
        seed_points.pop(0)
        #cv2.imshow("progress",outimg)
        #cv2.waitKey(1)
    return outimg

def on_mouse(event, x, y, flags, params):
    if event == cv2.EVENT_LBUTTONDOWN:
        print 'Seed: ' + str(x) + ', ' + str(y), img[y,x]
        clicks.append((y,x))
        
clicks = []
image = cv2.imread('lena.bmp', 0)
ret, img = cv2.threshold(image, 128, 255, cv2.THRESH_BINARY)
cv2.namedWindow('Input')
cv2.setMouseCallback('Input', on_mouse, 0, )
cv2.imshow('Input', img)
cv2.waitKey()
seed = clicks[-1]
out = region_growing(img, seed)
cv2.imshow('Region Growing', out)
cv2.waitKey()
cv2.destroyAllWindows()

这是点击她帽子左侧的结果:

【讨论】:

  • 感谢您的帮助。我复制了你写的代码,我得到了和上面一样的结果,我点击的地方有白色像素。你能告诉我你的输出结果吗?也许我做错了什么。
  • 添加了结果图像。如果您仍然遇到问题,我建议您在种子位置打印图像值,以确保您的 x 和 y 坐标没有混淆。这些结果来自我发布的确切代码。
  • 为什么要包含“img[coord[0], coord[1]] != 0” 或者它的功能是什么?或者为什么像素不能是黑色的?
  • region_growth 函数在已被阈值化的图像上运行,这意味着值是 0 或 255。所以该行可能是 if img[coord[0], coord[1]] == 255。或if img[coord[0], coord[1]] &gt; 0。它只是检查像素是否为黑色,因为在这种情况下这是边界条件。
  • 我认为最好不要为候选种子点列表重载内置的list函数。我会提出修改建议
【解决方案2】:

上面提出的解决方案在概念上是正确的,但从数值的角度来看,它们包含一些严重的问题,使它们在像素数上排序为 N^2。如果您可以将信息存储在提供随机访问的数组中,则无需在列表中搜索像素,并且可以对连通性函数进行cythonized。此外,如果能够提供您自己的相似度函数,那就太好了。

因此,这是我的建议,即在 Jupyter 笔记本中运行的改进版、绝对更快的版本:

导入的第一个单元格:

import numpy as np
import cv2

%pylab inline 

%load_ext Cython

第二个单元格(不要合并第一个):

%%cython
# Use %%cython -a for more verbose output, note %%cython should be on the first line in the cell!
def get_8_connected(int x, int y, shape):
    cdef int xmax = shape[0]-1
    cdef int ymax = shape[1]-1
    cdef int connected_pixel_x 
    cdef int connected_pixel_y
    cdef int dx, dy
    
    connected_pixels = list()
    
    for dx in range(3):
        for dy in range(3):
            connected_pixel_x  = x + dx - 1
            connected_pixel_y = y + dy - 1
            if connected_pixel_x < 0 or connected_pixel_x > xmax or \
                connected_pixel_y < 0 or connected_pixel_y > ymax or \
                (connected_pixel_x == x and connected_pixel_y == y):
                    pass
            else: 
                connected_pixels.append((connected_pixel_x,connected_pixel_y)) 
    return  connected_pixels

区域合并的第三个单元格

def region_growing(img, 
                   seed_points, 
                   test = lambda seed_x, seed_y, x, y, img, outimg : img[x,y] != 0,
                   colormap=None):
    
    processed = np.full((img.shape[0],img.shape[1]), False)
    
    if colormap is None:
        outimg = np.zeros_like(img)
    else:
        outimg = np.zeros((img.shape[0],img.shape[1],colormap.shape[1]),dtype=np.uint8)
    
    for index, pix in enumerate(seed_points):
        processed[pix[0], pix[1]] = True
        if colormap is None:
            outimg[pix[0], pix[1]] = img[pix[0], pix[1]]
        else:
            outimg[pix[0], pix[1]]  = colormap[index % len(colormap)]
    
    while(len(seed_points) > 0):
        pix = seed_points[0]
            
        for coord in get_8_connected(pix[0], pix[1], img.shape):
            if not processed[coord[0],coord[1]]:
                test_result = test(pix[0], pix[1], coord[0], coord[1], img, outimg)
                if test_result:
                    outimg[coord[0], coord[1]]  = outimg[pix[0], pix[1]]
                    if not processed[coord[0],coord[1]]:
                        seed_points.append(coord)
                    processed[coord[0],coord[1]] = True
                    
        seed_points.pop(0)
    return outimg

并且可以使用与之前相同的逻辑从另一个单元格调用它:

def on_mouse(event, x, y, flags, params):
    if event == cv2.EVENT_LBUTTONDOWN:
        print( 'Seed: ' + str(x) + ', ' + str(y), img[y,x])
        clicks.append((int(y), int(x)))
        
clicks = []
image = cv2.imread('lena.bmp', 0)
ret, img = cv2.threshold(image, 128, 255, cv2.THRESH_BINARY)
cv2.namedWindow('Input')
cv2.setMouseCallback('Input', on_mouse, 0, )
cv2.imshow('Input', img)
cv2.waitKey()
cv2.destroyAllWindows()

seed = clicks
out = region_growing(img, seed)
cv2.imshow('Region Growing', out)
cv2.waitKey()
cv2.destroyAllWindows()

有一些小的功能差异。输出中的一个区域要么由种子处的原始图像的值标记,要么由可选颜色图中的值标记。颜色图需要指定 RGB 颜色给定无符号 8 位整数。也可以传入定制的测试函数,替换:

test = lambda seed_x, seed_y, x, y, img, outimg : img[x,y] != 0

例如:

test = lambda seed_x, seed_y, x, y, img, outimg : abs(img[x,y] - img[seed_x, seed_y]) < 4

将产生所有与原始种子相连且强度步长低于 4 的像素。

在我的上下文中,它适用于单色和彩色图像。这既适用于 2d 数组,也适用于 3D 数组。

如果不能使用 Cython,则函数 get_8_connected 可以替换为:

def get_8_connected(x, y, shape):
    xmax = shape[0]-1
    ymax = shape[1]-1
    
    connected_pixels = list()
    
    for dx in range(3):
        for dy in range(3):
            connected_pixel_x  = x + dx - 1
            connected_pixel_y = y + dy - 1
            if connected_pixel_x < 0 or connected_pixel_x > xmax or \
                connected_pixel_y < 0 or connected_pixel_y > ymax or \
                (connected_pixel_x == x and connected_pixel_y == y):
                    pass
            else:
                connected_pixels.append((connected_pixel_x,connected_pixel_y))
    return  connected_pixels```

【讨论】:

    【解决方案3】:

    为 python 3.x 添加 () 比如:print("Some things")

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-18
      • 1970-01-01
      • 1970-01-01
      • 2010-10-27
      • 1970-01-01
      • 2010-10-21
      • 2016-05-28
      • 2014-08-01
      相关资源
      最近更新 更多