2

我想删除这个轮骨架标志的圆周(标志的最外周),除了里面的东西。我考虑一个函数 findcontours() 并删除我找到的最大轮廓

这是输入图像:

原始图像

骨架化:

骨架图像

但不幸的是,这是我的输出图像:

没有最大轮廓的骨架图像

为什么它不只保留 2 个交叉段,而一个段由很多点组成

from __future__ import division
import mahotas as mh
import pymorph as pm
import numpy as np

import os
import math

import cv2
from skimage import io
import scipy
from skimage import morphology

complete_path = 'DUPLInuova/ruote 7/e (11).jpg'

fork = mh.imread(complete_path)  
fork = fork[:,:,0]# extract one component, ex R 

#structuring elements
disk7 = pm.sedisk(3)#size 7x7: 7=3+1+3
disk5 = pm.sedisk(2)

#Just a simple thresholding with white background
bfork = fork < 150
bfork = mh.morph.dilate(bfork, disk7)

gray = cv2.imread(complete_path,0)
originale = gray
print("gray")
print(gray.shape)
cv2.imshow('graybin',gray)
cv2.waitKey()

ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY_INV) 
imgbnbin = thresh
print("shape imgbnbin")
print(imgbnbin.shape)
cv2.imshow('binaria',imgbnbin)
cv2.waitKey()
shape = list(gray.shape)
w = int( (shape[0]/100 )*5)
h = int((shape[1]/100)*5)
print(w)
print(h)
element = cv2.getStructuringElement(cv2.MORPH_CROSS,(w,h)) #con 4,4 si vede tutta la stella e riconosce piccoli oggetti
from skimage.morphology import square

graydilate = np.array(imgbnbin, dtype=np.float64)
graydilate = morphology.binary_dilation(graydilate, square(w))
graydilate = morphology.binary_dilation(graydilate, square(w))

out = morphology.skeletonize(graydilate>0)
img = out.astype(float)
cv2.imshow('scikitimage',img)
cv2.waitKey()
img = img.astype(np.uint8)
cv2.imshow('scikitconvert',img)
cv2.waitKey()

contours, hierarchy = cv2.findContours(img,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
print(len(contours))

# calculating area for deleting little signs
Areacontours = list()
calcarea = 0.0
unicocnt = 0.0
for i in range (0, len(contours)):
    area = cv2.contourArea(contours[i])
    #print("area")
    print(area)
    if (area > 90 ): 
        if (calcarea<area):
            calcarea = area
            unicocnt = contours[i]

cnt = unicocnt
ara = cv2.contourArea(cnt)
print("cnt")
print(ara)

#delete largest contour
cv2.drawContours(img,[cnt],0,(0,255,0),1)
cv2.imshow('img del contour',img)
cv2.waitKey()

更新解决方案(和新问题):

如果我在这行代码之后制作了骨架化的 img 的深层副本: img = img.astype(np.uint8) #after 骨架化过程

我可以将 find_contour 与复制的图像一起使用,并将 draw_contour 应用于原始图像,仅此而已!

我的问题是:

为什么找到轮廓编辑我的图像而我被迫使用临时图像?为什么 matplotlib 向我显示正确的结果而 cv2 imshow 不显示(它向我显示黑色图像)?

代码的新部分:

import copy
imgcontour = copy.copy(img)

imgcnt = img
contours, hierarchy = cv2.findContours(imgcontour,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE )
print(len(contours))

cnt = contours[0]

cv2.drawContours(img,[cnt],0,(0,0,0),1)

cv2.imshow('imgcv2black',img)
cv2.waitKey()

plt.gray()
plt.subplot(121)
plt.imshow(img)
plt.show()

matplotlib 中的正确结果

更新洪水文件+扩张:

Floodfill-dilate 程序是否正确?哪里错了?

a = np.ones((212,205), dtype=np.uint8)
#myMask = zeros(a.shape[0:2], dtype = uint8)

maskr = np.zeros(a.shape,np.uint8)
print(maskr.shape)
print(img[0])

cv2.floodFill(img,mask =maskr, seedPoint = (0,0), newVal = 1)
element = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3)) 
img = cv2.dilate(img, element)

cv2.imshow('flood',img)
cv2.waitKey()
plt.gray()
plt.subplot(121)
plt.imshow(img)
plt.show()

不幸的是,我得到了这个:

充盈+扩张

4

3 回答 3

1

一个非常简单的解决方案是标记图像中轮廓的组件。在这种情况下,您可以提取您直接感兴趣的轮廓。而且由于标签从拓扑外部开始,如果一个显示除第一个之外的所有轮廓标签,您应该得到结果。在轮廓已经闭合的情况下,不需要骨架!如果我们一开始的轮廓很厚,也可以进一步使用细化来获得细轮廓。

输入:我

在此处输入图像描述

标记轮廓:L = bwlabel(~I);

在此处输入图像描述

去除最大外轮廓:figure, imshow(L>1)

在此处输入图像描述

这必须可以在scikits连接组件标签设置中复制。

您还可以计算这些组件的大小并获取它们的长度(sum(sum(L==1)) 等等)

于 2013-11-04T03:14:23.610 回答
1

另一种可能实现所需结果的方法是在骨架化图像上进行泛光填充。由于外边界是封闭的,它将选择对象之外的所有像素。然后可以应用简单的膨胀来扩展填充区域以包括外环。将此作为蒙版应用,并删除任何已被洪水填充 + 膨胀的像素。这将只留下轮子的中心。

于 2013-05-03T02:18:57.250 回答
0

您还可以使用圆形霍夫变换来尝试定位轮辋,然后从那里开始工作。

于 2013-05-06T08:22:52.837 回答