以下是使用Python/OpenCV处理此问题的一种方法:
输入图像:
import cv2
import numpy as np
# read image as grayscale
img = cv2.imread('K.png', cv2.IMREAD_GRAYSCALE)
# threshold to binary
thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY)[1]
# apply morphology
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
# find contours - write black over all small contours
letter = morph.copy()
cntrs = cv2.findContours(morph, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cntrs = cntrs[0] if len(cntrs) == 2 else cntrs[1]
for c in cntrs:
area = cv2.contourArea(c)
if area < 100:
cv2.drawContours(letter,[c],0,(0,0,0),-1)
# do canny edge detection
edges = cv2.Canny(letter, 200, 200)
# write results
cv2.imwrite("K_thresh.png", thresh)
cv2.imwrite("K_morph.png", morph)
cv2.imwrite("K_letter.png", letter)
cv2.imwrite("K_edges.png", edges)
# show results
cv2.imshow("K_thresh", thresh)
cv2.imshow("K_morph", morph)
cv2.imshow("K_letter", letter)
cv2.imshow("K_edges", edges)
cv2.waitKey(0)
阈值化后的图像:
应用形态学开运算:
去除了小区域:
Canny边缘检测:
Threshold to binarize image
Apply erode and dilate individually because then you have more control over things like in-place or not, memory management if you write in C/C++. This matters when you have more than one iteration, to handle more noise.
Find contours. Based on use case, if you don't have loops (such as the loop in letter P), you can use find the only the external contours to optimise the code.
Iterate through the contours and remove any contour below threshold from the list of contours.
You already have the entire edge in the form of list of points here. If you can, use the edges as is or just create a blank image and draw all the valid contours with thickness 1 (only edges)
import cv2
import numpy as np
# read image as grayscale
img = cv2.imread('K.png', cv2.IMREAD_GRAYSCALE)
# threshold to binary
thresh = cv2.threshold(img, 1, 255, cv2.THRESH_BINARY)[1]
# apply morphology.
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.erode(thresh, kernel)
morph = cv2.dilate(morph, kernel)
# find contours & draw only valid contour edges on a black image
letter = np.zeros_like(img)
cntrs, hier = cv2.findContours(morph, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for idx, c in enumerate(cntrs):
area = cv2.contourArea(c)
if area > 100:
cv2.drawContours(letter, cntrs, idx, 255, 1, 8, hier)
# write results
cv2.imwrite("K_thresh.png", thresh)
cv2.imwrite("K_morph.png", morph)
cv2.imwrite("K_letter.png", letter)
# show results
cv2.imshow("K_thresh", thresh)
cv2.imshow("K_morph", morph)
cv2.imshow("K_letter", letter)
cv2.waitKey(0)
----> morph = cv2.erode(thresh, kernel)
。 TypeError: Expected Ptr<cv::UMat> for argument 'src'
调试发现,cv2.threshold方法返回的不仅仅是图像,所以我可以通过更改“阈值到二进制”的那一行来解决它:
r,thresh = cv2.threshold(img,1,255,cv2.THRESH_BINARY)
- Mourits de Beer首先使用Gaussian模糊
去除图像噪声,然后使用自动阈值Canny算法,如下代码:
def auto_canny(image, sigma=0.33):
v = np.median(image)
lower = int(max(0, (1.0 - sigma) * v))
upper = int(min(255, (1.0 + sigma) * v))
edged = cv2.Canny(image, lower, upper)
return edged
def main():
img_1 = cv2.imread('noise/1.png',cv2.IMREAD_GRAYSCALE)
blurred = cv2.GaussianBlur(img_1, (3, 3), 0)
auto_edge = auto_canny(blurred)
plt.imshow(auto_edge)
我希望这对你有所帮助
img_1
而不是 gray
?另外,您为什么要添加噪声来再次去除它? - DarK_FirefoX