ShapeMatching Using Fourier Descriptor

举报
风吹稻花香 发表于 2021/06/06 01:01:29 2021/06/06
【摘要】   github地址:https://github.com/AliceLeBrigant/ShapeMatching 这个代码上来就花轮廓,根据轮廓查找相似的,背景必须纯色,商用价值不高。 import numpy as npimport cv2 print("Shape Matching Using Fourier Descriptor") distThre...

 

github地址:https://github.com/AliceLeBrigant/ShapeMatching

这个代码上来就花轮廓,根据轮廓查找相似的,背景必须纯色,商用价值不高。


  
  1. import numpy as np
  2. import cv2
  3. print("Shape Matching Using Fourier Descriptor")
  4. distThreshold = 0.06
  5. ix, iy = -1, -1
  6. rect = (0, 0, 1, 1)
  7. manually = True
  8. temSeleteFlag = False
  9. temReadyFlag = False
  10. temConfirmFlag = False
  11. matchOverFlag = False
  12. templeteComVector = []
  13. sampleComVectors = []
  14. sampleContours = []
  15. # Manually select templete by mouse, On/Off by manually flag
  16. def selectTemplete(event, x, y, flags, param):
  17. global rect, temSeleteFlag, temReadyFlag, ix, iy
  18. if event == cv2.EVENT_LBUTTONDOWN and temReadyFlag == False:
  19. temSeleteFlag = True
  20. ix, iy = x, y
  21. elif event == cv2.EVENT_LBUTTONUP:
  22. if temReadyFlag == False and temSeleteFlag == True:
  23. # rect is selected templete ROI
  24. rect = (min(ix, x), min(iy, y), abs(ix - x), abs(iy - y))
  25. # draw a blue rectangle after selection
  26. cv2.rectangle(imgOri, (ix, iy), (x, y), (255, 0, 0), 2)
  27. temSeleteFlag = False
  28. temReadyFlag = True
  29. # Main findcontour function
  30. def getContours(img):
  31. imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  32. # Threshold white paper(background) to white pixel(255), word is actully black(0)
  33. retvalth, imgthreshold = cv2.threshold(imgray, 50, 255, cv2.THRESH_BINARY)
  34. # We want words are white, backgournd is black, easy for opencv findcontour function
  35. imgthresholdNot = cv2.bitwise_not(imgthreshold)
  36. # Dilation make all 6 to form a closed loop
  37. kernel = np.ones((5, 5), np.uint8)
  38. imgdilation = cv2.dilate(imgthresholdNot, kernel, iterations=2)
  39. # Must use EXTERNAL outer contours, Must use CHAIN_APPROX_NONE method(not change points)
  40. imgcontours, contours, hierarchy = cv2.findContours(imgdilation, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
  41. return contours
  42. # Get complex vector of templete contour
  43. def getTempleteCV():
  44. # This is the templete region that we select by mouse or default
  45. templeteROI = imgOricpy[rect[1]:rect[1] + rect[3], rect[0]:rect[0] + rect[2]]
  46. # Automatically find templete contour
  47. tpContour = getContours(templeteROI)
  48. for contour in tpContour:
  49. x, y, w, h = cv2.boundingRect(contour)
  50. for point in contour:
  51. # -x and -y are to make left and upper boundry start from 0
  52. templeteComVector.append(complex(point[0][0] - x, (point[0][1] - y)))
  53. # Get complex vectors of testees contours
  54. def getSampleCV():
  55. spContours = getContours(imgOricpy)
  56. # cv2.drawContours(imgOri, spContours, -1, (0, 0, 255), 1)
  57. for contour in spContours:
  58. sampleComVector = []
  59. x, y, w, h = cv2.boundingRect(contour)
  60. cv2.rectangle(imgOri, (x, y), (x + w, y + h), (100, 100, 100), 1)
  61. for point in contour:
  62. sampleComVector.append(complex(point[0][0] - x, (point[0][1] - y)))
  63. # sampleComVectors store CV of all testees contours
  64. sampleComVectors.append(sampleComVector)
  65. # sampleContours store all testees contours, same order with sampleComVectors
  66. sampleContours.append(contour)
  67. # Calculate fourier transform of templete CV
  68. def getempleteFD():
  69. return np.fft.fft(templeteComVector)
  70. # Calculate fourier transform of sample CVs
  71. def getsampleFDs():
  72. FDs = []
  73. for sampleVector in sampleComVectors:
  74. sampleFD = np.fft.fft(sampleVector)
  75. FDs.append(sampleFD)
  76. return FDs
  77. # Make fourier descriptor invariant to rotaition and start point
  78. def rotataionInvariant(fourierDesc):
  79. for index, value in enumerate(fourierDesc):
  80. fourierDesc[index] = np.absolute(value)
  81. return fourierDesc
  82. # Make fourier descriptor invariant to scale
  83. def scaleInvariant(fourierDesc):
  84. firstVal = fourierDesc[0]
  85. for index, value in enumerate(fourierDesc):
  86. fourierDesc[index] = value / firstVal
  87. return fourierDesc
  88. # Make fourier descriptor invariant to translation
  89. def transInvariant(fourierDesc):
  90. return fourierDesc[1:len(fourierDesc)]
  91. # Get the lowest X of frequency values from the fourier values.
  92. def getLowFreqFDs(fourierDesc):
  93. # frequence order returned by np.fft is (0, 0.1, 0.2, 0.3, ...... , -0.3, -0.2, -0.1)
  94. # Note: in transInvariant(), we already remove first FD(0 frequency)
  95. return fourierDesc[:5]
  96. # Get the final FD that we want to use to calculate distance
  97. def finalFD(fourierDesc):
  98. fourierDesc = rotataionInvariant(fourierDesc)
  99. fourierDesc = scaleInvariant(fourierDesc)
  100. fourierDesc = transInvariant(fourierDesc)
  101. fourierDesc = getLowFreqFDs(fourierDesc)
  102. return fourierDesc
  103. # Core match function
  104. def match(tpFD, spFDs):
  105. tpFD = finalFD(tpFD)
  106. # dist store the distance, same order as spContours
  107. dist = []
  108. font = cv2.FONT_HERSHEY_SIMPLEX
  109. for spFD in spFDs:
  110. spFD = finalFD(spFD)
  111. # Calculate Euclidean distance between templete and testee
  112. dist.append(np.linalg.norm(np.array(spFD) - np.array(tpFD)))
  113. x, y, w, h = cv2.boundingRect(sampleContours[len(dist) - 1])
  114. # Draw distance on image
  115. distText = str(round(dist[len(dist) - 1], 2))
  116. cv2.putText(imgOri, distText, (x, y - 8), font, 0.5, (0, 0, 0), 1, cv2.LINE_AA)
  117. # print str(len(dist)) + ": " + str(dist[len(dist)-1])
  118. # if distance is less than threshold, it will be good match.
  119. if dist[len(dist) - 1] < distThreshold:
  120. cv2.rectangle(imgOri, (x - 5, y - 5), (x + w + 5, y + h + 5), (40, 255, 0), 2)
  121. # --------------------------------------------------------------------------
  122. # Main loop
  123. imgOri = cv2.imread(r"E:\new/a2.jpg", 1)
  124. # imOricpy is for processing, imgOri is for showing
  125. imgOricpy = imgOri.copy()
  126. cv2.namedWindow("Original Image")
  127. if manually == True:
  128. # Manually select templete by mouse
  129. cv2.setMouseCallback("Original Image", selectTemplete)
  130. else:
  131. # Default region: upper 6
  132. rect = (50, 100, 130, 160)
  133. cv2.rectangle(imgOri, (50, 100), (180, 260), (255, 0, 0), 2)
  134. temReadyFlag = True
  135. temConfirmFlag = True
  136. while (True):
  137. cv2.imshow("Original Image", imgOri)
  138. if temReadyFlag == True and matchOverFlag == False and temConfirmFlag == True:
  139. # Get complex vector
  140. getTempleteCV()
  141. getSampleCV()
  142. # Get fourider descriptor
  143. tpFD = getempleteFD()
  144. sampleFDs = getsampleFDs()
  145. # real match function
  146. match(tpFD, sampleFDs)
  147. matchOverFlag = True
  148. cv2.imwrite("result.jpg", imgOri)
  149. # Resize img for showing
  150. imgShow = cv2.resize(imgOri, None, fx=0.66, fy=0.66, interpolation=cv2.INTER_CUBIC)
  151. cv2.imshow("Small Size Show", imgShow)
  152. key = cv2.waitKey(1) & 0xFF
  153. if key == ord('y') or key == ord('Y'):
  154. # Press Y for templete confirm once mouse selection done
  155. temConfirmFlag = True
  156. elif key == ord('q') or key == ord('Q'):
  157. # Press q for quit
  158. break
  159. cv2.destroyAllWindows()

 

文章来源: blog.csdn.net,作者:网奇,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/jacke121/article/details/95377492

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。