检测彩色图片OpenCV的边缘
Detecting the edge of a colorful picture OpenCV
我是 CV 新手,刚刚学会了如何检测纸张的边缘。我想尝试更复杂的东西。所以我从一个电影网站截屏,想从该网站检测海报。如果背景颜色与海报不同,效果很好。但是当它们颜色相似时,我找不到图片的边缘
cv2.findContours()
原图是:
Poster
而我所做的是:
img = cv2.imread('pic5.jpg')
orig = img.copy()
image = orig
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
binary = cv2.medianBlur(gray,3)
# blur = cv2.GaussianBlur(binary, (5, 5), 0)
# ret, binary = cv2.threshold(blur,127,255,cv2.THRESH_TRUNC)
edged = cv2.Canny(binary, 3, 30)
show(edged)
# detect edge
contours, hierarchy = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cnts = sorted(contours, key=cv2.contourArea, reverse=True)[:5]
#
for c in cnts:
# approx
peri = cv2.arcLength(c, True)
eps = 0.02
approx = cv2.approxPolyDP(c, eps*peri, True)
# detect square (4 points)
if len(approx) == 4:
screenCnt = approx
break
res = cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 2)
show(orig)
结果是:
after preprocess
What I detect
不知道这个方法行不行。是否可以根据背景颜色检测出正方形部分(不考虑海报的颜色)?
您可以继续 edged
结果,并使用闭合形态学操作来闭合小间隙。
我建议您不要使用 approxPolyDP
搜索矩形,而是查找最大连通分量(或最大轮廓)的边界矩形。
在我的代码示例中,由于外部边界线,我将 findContours
替换为 connectedComponentsWithStats
。
您可以使用开放形态操作来摆脱外部线(并使用继续使用findContours
)。
您也可以使用 approxPolyDP
来优化结果。
这是代码示例:
import numpy as np
import cv2
img = cv2.imread('pic5.png')
orig = img.copy()
image = orig
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
binary = cv2.medianBlur(gray, 3)
edged = cv2.Canny(binary, 3, 30)
edged = cv2.morphologyEx(edged, cv2.MORPH_CLOSE, np.ones((5,5))) # Close small gaps
#contours, hierarchy = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
#c = max(contours, key=cv2.contourArea) # Get the largest contour
#x, y, w, h = cv2.boundingRect(c) # Find bounding rectangle.
nb_components, output, stats, centroids = cv2.connectedComponentsWithStats(edged, 8) # finding components
#
# Find the largest non background component.
# Note: range() starts from 1 since 0 is the background label.
max_label, max_size = max([(i, stats[i, cv2.CC_STAT_AREA]) for i in range(1, nb_components)], key=lambda x: x[1])
# Find bounding rectangle of largest connected component.
x = stats[max_label, cv2.CC_STAT_LEFT]
y = stats[max_label, cv2.CC_STAT_TOP]
w = stats[max_label, cv2.CC_STAT_WIDTH]
h = stats[max_label, cv2.CC_STAT_HEIGHT]
res = image.copy()
cv2.rectangle(res, (x, y), (x+w, y+h), (0, 255, 0), 2) # Draw a rectangle
cv2.imshow('edged', edged)
cv2.imshow('res', res)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
edged
:
res
:
我是 CV 新手,刚刚学会了如何检测纸张的边缘。我想尝试更复杂的东西。所以我从一个电影网站截屏,想从该网站检测海报。如果背景颜色与海报不同,效果很好。但是当它们颜色相似时,我找不到图片的边缘
cv2.findContours()
原图是:
Poster
而我所做的是:
img = cv2.imread('pic5.jpg')
orig = img.copy()
image = orig
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
binary = cv2.medianBlur(gray,3)
# blur = cv2.GaussianBlur(binary, (5, 5), 0)
# ret, binary = cv2.threshold(blur,127,255,cv2.THRESH_TRUNC)
edged = cv2.Canny(binary, 3, 30)
show(edged)
# detect edge
contours, hierarchy = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cnts = sorted(contours, key=cv2.contourArea, reverse=True)[:5]
#
for c in cnts:
# approx
peri = cv2.arcLength(c, True)
eps = 0.02
approx = cv2.approxPolyDP(c, eps*peri, True)
# detect square (4 points)
if len(approx) == 4:
screenCnt = approx
break
res = cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 2)
show(orig)
结果是: after preprocess What I detect
不知道这个方法行不行。是否可以根据背景颜色检测出正方形部分(不考虑海报的颜色)?
您可以继续 edged
结果,并使用闭合形态学操作来闭合小间隙。
我建议您不要使用 approxPolyDP
搜索矩形,而是查找最大连通分量(或最大轮廓)的边界矩形。
在我的代码示例中,由于外部边界线,我将 findContours
替换为 connectedComponentsWithStats
。
您可以使用开放形态操作来摆脱外部线(并使用继续使用findContours
)。
您也可以使用 approxPolyDP
来优化结果。
这是代码示例:
import numpy as np
import cv2
img = cv2.imread('pic5.png')
orig = img.copy()
image = orig
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
binary = cv2.medianBlur(gray, 3)
edged = cv2.Canny(binary, 3, 30)
edged = cv2.morphologyEx(edged, cv2.MORPH_CLOSE, np.ones((5,5))) # Close small gaps
#contours, hierarchy = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
#c = max(contours, key=cv2.contourArea) # Get the largest contour
#x, y, w, h = cv2.boundingRect(c) # Find bounding rectangle.
nb_components, output, stats, centroids = cv2.connectedComponentsWithStats(edged, 8) # finding components
#
# Find the largest non background component.
# Note: range() starts from 1 since 0 is the background label.
max_label, max_size = max([(i, stats[i, cv2.CC_STAT_AREA]) for i in range(1, nb_components)], key=lambda x: x[1])
# Find bounding rectangle of largest connected component.
x = stats[max_label, cv2.CC_STAT_LEFT]
y = stats[max_label, cv2.CC_STAT_TOP]
w = stats[max_label, cv2.CC_STAT_WIDTH]
h = stats[max_label, cv2.CC_STAT_HEIGHT]
res = image.copy()
cv2.rectangle(res, (x, y), (x+w, y+h), (0, 255, 0), 2) # Draw a rectangle
cv2.imshow('edged', edged)
cv2.imshow('res', res)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
edged
:
res
: