2013-02-16 145 views
0

我試圖通過識別原始圖像的模板將圖像分成幾個子圖像,然後複製匹配這些模板的區域。我是opencv的新手!我已經確定使用的子圖像:在opencv和python中複製圖像的一部分

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)保存到分隔的文件。

我該怎麼做?我已經閱讀了一些關於輪廓的內容,但我不確定如何使用它。理想情況下,我想輪廓八角形。

非常感謝您的幫助!

回答

4

如果模板匹配正在爲您工作,請堅持下去。舉例來說,我認爲下面的模板:

enter image description here

然後,我們可以預處理,以使之成爲一個二進制文件和丟棄的小部件的輸入。在此步驟之後,執行模板匹配。然後就是通過丟棄關鍵字來過濾比賽(我使用了虛擬方法,所以如果比賽太多,你可能會花費一些時間)。在我們確定哪些點相距很遠(從而識別不同的六邊形)之後,我們可以通過以下方式對它們進行微調:

  • 按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(但當時是沒有意義的光柵順序六邊形排序)。

這裏是一個將被削減爲你的兩個例子,而無需修改上面的代碼不同區域的表示:

enter image description hereenter image description here

+0

非常感謝您的回答!我得到以下錯誤:第23行,在 _,l [i] = cv2.threshold(cv2.COLt_BGR2GRAY), 錯誤:/ home/abuild/rpmbuild/BUILD/OpenCV -2.4.1/modules/imgproc/src/color.cpp:3205:error:(-215)scn == 3 || scn == 4在函數cvtColor中,我真的不知道如何解決它...你對什麼問題有什麼想法嗎? – 2013-02-16 17:18:49

+0

@AlbertVonpupp是因爲模板或輸入已經有單個通道而引起的。如果你的模板圖像只有一個通道並且已經是二進制的,你可以添加在'_,l [i] = cv2.threshold(...)'之後有一個'break'語句,這樣只會處理輸入,在這種情況下,你可以重寫那個部分來消除'for'循環。 – mmgp 2013-02-16 18:04:42

+0

這是一個愚蠢的錯誤,我使用了一個錯誤的文件名。我修復並在第50行(在第一個循環之後)用一個斷點運行它。 e ptlist應該有些東西,但是是空的。如果我將閾值設置爲0.95,它似乎只適用於第二列八角形。當我用這個圖像運行它時https://github.com/vonpupp/opencv-learning/blob/master/test01.jpeg它不會產生threshold = 0.99的任何輸出,並且它似乎與閾值= 0.95一起掛起。我將在稍後將代碼上傳到git倉庫併發布鏈接。 – 2013-02-16 18:40:09

1

對不起,我不明白你的問題,你如何與matchTemplate和Contours相關。

無論如何,下面是使用輪廓的小技巧。假設您的其他圖像也與您提供的圖像一樣。我不確定它是否適用於其他圖像。但我認爲這將有助於創業。親自嘗試一下,做出必要的調整和修改。

我做了什麼:

1 - 我需要八角形的邊緣。所以Thresholded圖像使用Otsu和應用擴張和侵蝕(或使用任何你喜歡的方法,適用於所有圖像,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() 

這些八角形6將存儲作爲分開的文件。

希望它有幫助!

+0

非常感謝您的快速回答阿比德。我用這個代碼來匹配模板https://github.com/vonpupp/opencv-learning/blob/master/multimatch02.py。你的代碼真棒,它會幫助我很多。我使用matchtemplate方法來匹配八角形,因爲你可以看到輪廓也將匹配底部信息的一部分(應該避免)。我只需要在最後得到35張圖片(來自八角形)。再次感謝您的大力幫助。我會嘗試使用matchTemplate中的輪廓來調整我的代碼。 – 2013-02-16 12:11:19

+0

我忘記了,按照有序的方式(從上到下,從左到右)得到八角形也很重要。我可以用一種快速而骯髒的方式來過濾最細微的圖像。代碼:https://github.com/vonpupp/opencv-learning/blob/master/contour01.py – 2013-02-16 12:36:26

+0

使用cv2.moments()可以找到這些八角形的質心。然後根據它們的(x,y)座標對這些輪廓進行排序。希望你能做到這一點。要找到時刻,請閱讀這篇文章:http://goo.gl/tvy9r – 2013-02-16 13:15:41