템플릿 일치가 제대로 작동하는 경우 계속 사용하세요.
그런 다음, 우리가 진 하나하고 작은 부품을 폐기하기 위해 입력을 사전 처리 할 수 있습니다 : 예를 들어, 나는 다음과 같은 템플릿을 고려했다. 이 단계 후에 템플릿 일치가 수행됩니다. 그렇다면 가까운 것들을 버리는 방법으로 경기를 필터링하는 문제입니다. (나는 더미 방법을 사용했습니다. 너무 많은 경기가 있다면 시간이 좀 걸릴 것입니다.)어느 점이 떨어져 있는지를 결정한 후 (따라서 다른 육각형을 식별하는 경우), 다음과 같은 방법으로 조금씩 조정할 수 있습니다.
- y 좌표로 정렬;
- 인접한 두 항목이 너무 가까운 y 좌표에서 시작하면 둘 다 같은 y 좌표로 설정하십시오.
이제 작곡이 래스터 순서로 완료되도록 적절한 순서로이 포인트 목록을 정렬 할 수 있습니다. 자르기 부분은 numpy
에 의해 제공되는 슬라이싱을 사용하여 쉽게 달성됩니다.
import sys
import cv2
import numpy
outbasename = 'hexagon_%02d.png'
img = cv2.imread(sys.argv[1])
template = cv2.cvtColor(cv2.imread(sys.argv[2]), cv2.COLOR_BGR2GRAY)
theight, twidth = template.shape[:2]
# Binarize the input based on the saturation and value.
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
saturation = hsv[:,:,1]
value = hsv[:,:,2]
value[saturation > 35] = 255
value = cv2.threshold(value, 0, 255, cv2.THRESH_OTSU)[1]
# Pad the image.
value = cv2.copyMakeBorder(255 - value, 3, 3, 3, 3, cv2.BORDER_CONSTANT, value=0)
# Discard small components.
img_clean = numpy.zeros(value.shape, dtype=numpy.uint8)
contours, _ = cv2.findContours(value, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
for i, c in enumerate(contours):
area = cv2.contourArea(c)
if area > 500:
cv2.drawContours(img_clean, contours, i, 255, 2)
def closest_pt(a, pt):
if not len(a):
return (float('inf'), float('inf'))
d = a - pt
return a[numpy.argmin((d * d).sum(1))]
match = cv2.matchTemplate(img_clean, template, cv2.TM_CCORR_NORMED)
# Filter matches.
threshold = 0.8
dist_threshold = twidth/1.5
loc = numpy.where(match > threshold)
ptlist = numpy.zeros((len(loc[0]), 2), dtype=int)
count = 0
print "%d matches" % len(loc[0])
for pt in zip(*loc[::-1]):
cpt = closest_pt(ptlist[:count], pt)
dist = ((cpt[0] - pt[0]) ** 2 + (cpt[1] - pt[1]) ** 2) ** 0.5
if dist > dist_threshold:
ptlist[count] = pt
count += 1
# Adjust points (could do for the x coords too).
ptlist = ptlist[:count]
view = ptlist.ravel().view([('x', int), ('y', int)])
view.sort(order=['y', 'x'])
for i in xrange(1, ptlist.shape[0]):
prev, curr = ptlist[i - 1], ptlist[i]
if abs(curr[1] - prev[1]) < 5:
y = min(curr[1], prev[1])
curr[1], prev[1] = y, y
# Crop in raster order.
view.sort(order=['y', 'x'])
for i, pt in enumerate(ptlist, start=1):
cv2.imwrite(outbasename % i,
img[pt[1]-2:pt[1]+theight-2, pt[0]-2:pt[0]+twidth-2])
print 'Wrote %s' % (outbasename % i)
당신은 육각형의 윤곽을 원한다면, img_clean
대신 img
에 자르 (그러나 다음 래스터 순서로 육각형을 정렬하는 데 의미가있다).
답변 해 주셔서 감사합니다. 다음과 같은 오류가 발생했습니다 : _l [i] = cv2.threshold (cv2.cvtColor (l [i], cv2.COLOR_BGR2GRAY), 오류 :/home/abuild/rpmbuild/BUILD/OpenCV -2.4.1/modules/imgproc/src/color.cpp : 3205 : 오류 : (-215) scn == 3 || scn == 4 함수 cvtColor에서. 솔직히 고칠 방법에 대한 단서가 없습니다. ... 문제의 원인에 대해 알고 계신가요? –
@AlbertVonpupp 템플릿 또는 입력에 이미 하나의 채널이 있기 때문에 발생합니다. 템플릿의 이미지에 단일 채널이 있고 이미 이진 파일 인 경우 추가 할 수 있습니다. '_, l [i] = cv2.threshold (...)'바로 다음에'break' 문을 쓰면 입력 만 처리하게됩니다. – mmgp
바보 같은 실수 였는데, 잘못된 파일 이름을 사용하고있었습니다. 첫 번째 루프 이후에 50 번째 줄에 중단 점을 지정하여 실행했습니다. 그 ptlist 뭔가가 있어야하지만 비어 있습니다. 임계 값을 0.95로 설정하면 팔각형의 두 번째 열에 대해서만 작동하는 것 같습니다. 이 이미지를 https://github.com/vonpupp/opencv-learning/blob/master/test01.jpeg와 함께 실행하면 threshold = 0.99로 출력이 생성되지 않고 threshold = 0.95로 정지 한 것처럼 보입니다. . 나중에 코드를 git repo에 업로드하고 링크를 게시합니다. –