get_plant_size.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. # coding=utf-8
  2. from scipy.spatial import distance as dist
  3. from imutils import perspective
  4. from imutils import contours
  5. import numpy as np
  6. import argparse
  7. import imutils
  8. import cv2
  9. import time
  10. # 定義一個中點函數,後面會用到
  11. def midpoint(ptA, ptB):
  12. return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)
  13. # 讀取輸入圖片
  14. image = cv2.imread("test3.jpg")
  15. # 建立一個黑色背景的圖片
  16. bg_img = np.zeros((image.shape[0], image.shape[1] // 2, 3), np.uint8)
  17. # 設定正方形的邊長
  18. length = int(2 / 2.54 * image.shape[1] / 2)
  19. # 畫出正方形
  20. cv2.rectangle(bg_img, (bg_img.shape[1] // 2 - length // 2, bg_img.shape[0] // 2 - length // 2),
  21. (bg_img.shape[1] // 2 + length // 2, bg_img.shape[0] // 2 + length // 2), (255, 255, 255), 2)
  22. # 將原始圖片與正方形圖案合併在一起
  23. image = np.concatenate((bg_img, image), axis=1)
  24. cv2.imshow('Result', image)
  25. cv2.waitKey(0)
  26. # 輸入圖片灰度化
  27. gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  28. # 對灰度圖片執行高斯濾波
  29. gray = cv2.GaussianBlur(gray, (7, 7), 0)
  30. # 對濾波結果做邊緣檢測獲取目標
  31. edged = cv2.Canny(gray, 50, 100)
  32. # 使用膨脹和腐蝕操作進行閉合對象邊緣之間的間隙
  33. edged = cv2.dilate(edged, None, iterations=1)
  34. edged = cv2.erode(edged, None, iterations=1)
  35. # 在邊緣圖像中尋找物體輪廓(即物體)
  36. cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
  37. cv2.CHAIN_APPROX_SIMPLE)
  38. cnts = imutils.grab_contours(cnts)
  39. # 對輪廓按照從左到右進行排序處理
  40. (cnts, _) = contours.sort_contours(cnts)
  41. # 初始化 'pixels per metric'
  42. pixelsPerMetric = None
  43. # 循環遍歷每一個輪廓
  44. for c in cnts:
  45. # 如果當前輪廓的面積太少,認為可能是噪聲,直接忽略掉
  46. if cv2.contourArea(c) < 100:
  47. continue
  48. # 根據物體輪廓計算出外切矩形框
  49. orig = image.copy()
  50. box = cv2.minAreaRect(c)
  51. box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)
  52. box = np.array(box, dtype="int")
  53. # 按照top-left, top-right, bottom-right, bottom-left的順序對輪廓點進行排序,並繪製外切的BB,用綠色的線來表示
  54. box = perspective.order_points(box)
  55. cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2)
  56. # 繪製BB的4個頂點,用紅色的小圓圈來表示
  57. for (x, y) in box:
  58. cv2.circle(orig, (int(x), int(y)), 5, (0, 0, 255), -1)
  59. # 分別計算top-left 和top-right的中心點和bottom-left 和bottom-right的中心點坐標
  60. (tl, tr, br, bl) = box
  61. (tltrX, tltrY) = midpoint(tl, tr)
  62. (blbrX, blbrY) = midpoint(bl, br)
  63. # 分別計算top-left和top-right的中心點和top-righ和bottom-right的中心點坐標
  64. (tlblX, tlblY) = midpoint(tl, bl)
  65. (trbrX, trbrY) = midpoint(tr, br)
  66. # 繪製BB的4條邊的中心點,用藍色的小圓圈來表示
  67. cv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)
  68. cv2.circle(orig, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1)
  69. cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)
  70. cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)
  71. # 在中心點之間繪製直線,用紫紅色的線來表示
  72. cv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY)),
  73. (255, 0, 255), 2)
  74. cv2.line(orig, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),
  75. (255, 0, 255), 2)
  76. # 計算兩個中心點之間的歐氏距離,即圖片距離
  77. dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
  78. dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
  79. # 初始化測量指標值,參考物體在圖片中的寬度已經通過歐氏距離計算得到,參考物體的實際大小已知
  80. if pixelsPerMetric is None:
  81. pixelsPerMetric = dB / (1.968503 *2.54) #大約5公分=1.968503英吋
  82. # 計算目標的實際大小(寬和高),用英尺來表示
  83. dimA = dA / pixelsPerMetric
  84. dimB = dB / pixelsPerMetric
  85. # 在圖片中繪製結果
  86. cv2.putText(orig, "{:.1f}cm".format(dimB),
  87. (int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,
  88. 0.65, (255, 255, 255), 2)
  89. cv2.putText(orig, "{:.1f}cm".format(dimA),
  90. (int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,
  91. 0.65, (255, 255, 255), 2)
  92. print('長:',"{:.1f}cm".format(dimB))
  93. print('寬:',"{:.1f}cm".format(dimA))
  94. now_time = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(time.time()))
  95. save_pic_name = now_time + '_' + '.jpg'
  96. cv2.imwrite(save_pic_name, orig)
  97. path = 'size_output.txt'
  98. with open(path, 'a') as f:
  99. f.write('長:'+"{:.1f}cm".format(dimB)+' 寬:'+"{:.1f}cm".format(dimA) + '\n')
  100. # 顯示結果
  101. #cv2.namedWindow('Image', 0)
  102. cv2.namedWindow("Image", cv2.WINDOW_NORMAL)
  103. cv2.resizeWindow("Image", 800, 600)
  104. cv2.imshow("Image", orig)
  105. cv2.waitKey(0)