[英]Copy a part of an image in opencv and python
我正在嘗試使用opencv通過識別原始圖像的模板將圖像分為幾個子圖像,然后復制與這些模板匹配的區域。 我是opencv的新手! 我使用以下方法確定了子圖像:
result = cv2.matchTemplate(img, template, cv2.TM_CCORR_NORMED)
經過一些清理后,我得到了一個稱為點的元組列表,在其中迭代顯示矩形。 tw和th分別是模板的寬度和高度。
for pt in points:
re = cv2.rectangle(img, pt, (pt[0] + tw, pt[1] + th), 0, 2)
print('%s, %s' % (str(pt[0]), str(pt[1])))
count+=1
我要完成的工作是將八邊形( https://dl.dropbox.com/u/239592/region01.png )保存到單獨的文件中。
我怎樣才能做到這一點? 我已經讀過一些有關輪廓的信息,但是我不確定如何使用它。 理想情況下,我想繪制八邊形輪廓。
非常感謝你的幫助!
如果模板匹配對您有用,請堅持下去。 例如,我考慮了以下模板:
然后,我們可以對輸入進行預處理,以使其成為二進制輸入並丟棄小的組件。 在此步驟之后,將執行模板匹配。 然后是通過丟棄接近的匹配項來過濾匹配項的問題(為此,我使用了一種偽方法,因此,如果匹配項太多,您可能會花一些時間)。 在確定了哪些點相距很遠(從而確定了不同的六邊形)之后,我們可以通過以下方式對其進行較小的調整:
現在,您可以按適當的順序對該點列表進行排序,以便以柵格順序進行裁剪。 使用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
上進行裁剪(但是按柵格順序對六邊形進行排序是沒有意義的)。
這是兩個示例在不修改上面的代碼的情況下將被剪切的不同區域的表示:
抱歉,我對您如何將matchTemplate和Contours聯系起來不甚了解。
無論如何,下面是使用輪廓的小技巧。 假設您的其他圖像也與您提供的圖像相同。 我不確定它是否可以與您的其他圖像一起使用。 但是我認為這將對初創公司有所幫助。 自己嘗試一下,並進行必要的調整和修改。
我做了什么 :
1-我需要八邊形的邊緣。 因此,請使用Otsu進行“閾值圖像”處理並應用散布和腐蝕(或使用您喜歡的任何方法都適用於所有圖像, beware of the edges in left edge of image
圖像beware of the edges in left edge of image
)。
2-然后找到輪廓(有關輪廓的更多信息: http : //goo.gl/r0ID0
3-對於每個輪廓,找到其凸包,找到其面積(A)和周長(P)
4-對於完美的八邊形 , P*P/A = 13.25 approximately
。 我在這里使用它並剪切並保存。
5-您可以看到裁剪它也會刪除八邊形的某些邊緣。 如果需要,請調整裁剪尺寸。
代碼:
import cv2
import numpy as np
img = cv2.imread('region01.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
thresh = cv2.dilate(thresh,None,iterations = 2)
thresh = cv2.erode(thresh,None)
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
number = 0
for cnt in contours:
hull = cv2.convexHull(cnt)
area = cv2.contourArea(hull)
P = cv2.arcLength(hull,True)
if ((area != 0) and (13<= P**2/area <= 14)):
#cv2.drawContours(img,[hull],0,255,3)
x,y,w,h = cv2.boundingRect(hull)
number = number + 1
roi = img[y:y+h,x:x+w]
cv2.imshow(str(number),roi)
cv2.imwrite("1"+str(number)+".jpg",roi)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
那六個八邊形將作為單獨的文件存儲。
希望能幫助到你 !!!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.