Python,OpenCV提取图片中的多个茄子种子轮廓,并按从左到右排序后显示
生活随笔
收集整理的這篇文章主要介紹了
Python,OpenCV提取图片中的多个茄子种子轮廓,并按从左到右排序后显示
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
Python,OpenCV提取圖片中的多個(gè)茄子種子輪廓,并按從左到右排序后顯示
- 1. 效果圖
- 2. 源碼
寫這篇博客源于博友的提問,期望把下圖中的多個(gè)茄子種子按從左到右的順序提取出來;
1. 效果圖
在每顆茄子種子上繪制綠色圓形,效果圖如下:
在每顆茄子種子上繪制藍(lán)色矩形,效果圖如下:
原圖 VS 灰度圖 VS 高斯模糊圖 VS 閾值化圖 VS 最終效果圖如下
原圖 — 轉(zhuǎn)灰度圖 忽略色彩對(duì)提取輪廓的影響;
灰度圖 — 高斯模糊后圖 忽略高頻噪音的影響;
高斯模糊圖 — 閾值化圖 使提取物體與背景明顯的被分為前景和背景;
閾值化圖 ——應(yīng)用輪廓檢測(cè),獲取輪廓,并簡單過濾,繪制矩形邊界框在輪廓上;
增加根據(jù)輪廓從左到右排序,未排序 VS 排序效果圖如下:
由于只是單純根據(jù)輪廓的坐標(biāo)x排序,所以并不是理所當(dāng)然的 從左到右,從上到下的效果。
輪廓中心點(diǎn)從左到右排序,從右到左排序
從上到下排序,從下到上排序
從上到下+從左到右排序
從左到右+從上到下排序
2. 源碼
# 提取圖片中的每個(gè)茄子種子,提供了倆種方法,一種單純的python圖片剪裁,效果并不好(圖片簡單的裁剪,有的種子會(huì)剪裁殘缺,有的會(huì)包含倆個(gè))
# 另一種先預(yù)處理圖像:轉(zhuǎn)灰度圖、高斯模糊、閾值化、輪廓提取、輪廓過濾、輪廓排序,繪制效果圖;效果要好很多。
import argparseimport cv2
import numpy as np# 簡單分割,效果并不好
def crop(img):qz1 = img[:30, :40]width = 40height = 30cv2.imshow("qz", qz1)cv2.waitKey(0)for w in range(0, int(320 / width)):for h in range(0, int(240 / height)):print(w * width, h * height, (w + 1) * width, (h + 1) * height)cv2.imshow(str(w) + "" + str(h), img[h * height:(h + 1) * height, w * width:(w + 1) * width])cv2.waitKey(0)cv2.destroyAllWindows()# 輪廓排序(上下左右組合排列) 從左到右從上到下 從上到下從左到右
def sort_cnts_xy(cnts, method="x-combine-y"):i = 1j = 0if (method == "y-combine-x"):i = 0j = 1# 構(gòu)建中心點(diǎn)list 并使用python魔術(shù)lambda表達(dá)式進(jìn)行排序ms = [cv2.moments(c) for c in cnts]centers = [[int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"])] for M in ms]# print(centors)# my_sorted_list = sorted(centors, key=lambda item: (item[0], item[1]))# print(my_sorted_list)# 先x 后y 0,1, 先y后x, 1 0(cnts, boundingBoxes) = zip(*sorted(zip(cnts, centers),key=lambda b: (b[1][i], b[1][j])))# 返回排序后的輪廓和邊界框return (cnts, boundingBoxes)# 輪廓排序 默認(rèn)從左到右
# --cnts 待排序的輪廓列表
# --method 排序方法 自上而下,從左到右等
def sort_cnts(cnts, method="left-to-right"):if (method == "x-combine-y" or method == "y-combine-x"):return sort_cnts_xy(cnts, method)# 初始化反向標(biāo)志和排序索引reverse = Falsei = 0# 處理是否需要逆向排序if method == "right-to-left" or method == "bottom-to-top":reverse = True# 處理時(shí)根據(jù)邊界框的x坐標(biāo)排序還是y坐標(biāo)排序,如果是自上而下或者自下而上則需要根據(jù)y坐標(biāo)排序而不是x坐標(biāo)if method == "top-to-bottom" or method == "bottom-to-top":i = 1# 構(gòu)建邊界框list 并使用python魔術(shù)lambda表達(dá)式進(jìn)行排序boundingBoxes = [cv2.boundingRect(c) for c in cnts](cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),key=lambda b: b[1][i], reverse=reverse))# 返回排序后的輪廓和邊界框return (cnts, boundingBoxes)# 繪制輪廓ID號(hào)
def draw_contour(image, c, i):# 計(jì)算輪廓區(qū)域的中心,并繪制?代表中心M = cv2.moments(c)cX = int(M["m10"] / M["m00"])cY = int(M["m01"] / M["m00"])# 在圖像上繪制輪廓數(shù)cv2.putText(image, "{}".format(i + 1), (cX - 10, cY - 10), cv2.FONT_HERSHEY_SIMPLEX,0.5, (0, 255, 255), 1)(x, y), radius = cv2.minEnclosingCircle(c)center = (int(x), int(y))radius = int(radius)cv2.circle(image, center, radius, (0, 255, 0), 1)# 返回繪制了輪廓數(shù)的圖像return image# 構(gòu)建命令行參數(shù)及解析
# --image 輸入圖像路徑
# --preprocess:預(yù)處理類型,thresh或blur
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=False, default='images/qz2.jpg',help="path to input image to be OCR'd")
ap.add_argument("-p", "--preprocess", required=False, type=str, default="thresh",help="type of preprocessing to be done")
ap.add_argument("-m", "--method", required=False, default='y-combine-x',help="Sorting method")
args = vars(ap.parse_args())image = cv2.imread(args["image"])
origin = image.copy()
print(image.shape)
cv2.imshow("origin", image)# 法一:圖片簡單的裁剪,有的種子會(huì)剪裁殘缺,有的會(huì)包含倆個(gè)
# crop(image)gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow("gray", gray)# 預(yù)處理以便將前景與背景分割開來
# 檢測(cè)是該用閾值還是模糊預(yù)處理步驟
# 高斯模糊處理以減少高頻噪聲
blurred = cv2.GaussianBlur(gray, (3, 3), 0)
cv2.imshow("blurred", blurred)thresh = cv2.threshold(gray, 140, 255, cv2.THRESH_BINARY)[1]cv2.imshow("thresh", thresh)
contours, hierarchy = cv2.findContours(thresh, 1, 2)
print(len(contours))# 根據(jù)面積過濾掉面積過大、過小的不合法輪廓
cnts = [cnt for cnt in contours if cv2.contourArea(cnt) > 14 and cv2.contourArea(cnt) < 150]
print(len(cnts))for i, cnt in enumerate(cnts):# print(i, area)M = cv2.moments(cnt)cX = int(M["m10"] / M["m00"])cY = int(M["m01"] / M["m00"])# 在圖像上繪制輪廓及中心# cv2.drawContours(image, [cnt], -1, (0, 255, 0), 2)# cv2.circle(image, (cX, cY), 7, (0, 0, 255), -1)cv2.putText(image, str(i + 1), (cX - 10, cY - 10),cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 255), 1)# 在圖像上繪制最小外接圓(綠色)# (x, y), radius = cv2.minEnclosingCircle(cnt)# center = (int(x), int(y))# radius = int(radius)# cv2.circle(image, center, radius, (0, 255, 0), 1)# 在圖像上繪制面積最小外接矩形藍(lán)色rect = cv2.minAreaRect(cnt)box = cv2.boxPoints(rect)box = np.int0(box)cv2.drawContours(image, [box], 0, (255, 0, 0), 1)cv2.imshow("res", image)
cv2.waitKey(0)# 根據(jù)提供的方法對(duì)輪廓進(jìn)行排序
(cnts, boundingBoxes) = sort_cnts(cnts, method=args["method"])# 遍歷排序后的輪廓,并繪制在圖像上
for (i, c) in enumerate(cnts):draw_contour(origin, c, i)# 展示排序后的輸出圖像
cv2.imshow("Sorted " + str(args['method']) + " res", origin)
cv2.waitKey(0)
cv2.destroyAllWindows()
總結(jié)
以上是生活随笔為你收集整理的Python,OpenCV提取图片中的多个茄子种子轮廓,并按从左到右排序后显示的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenCV中的光流及视频特征点追踪
- 下一篇: 试管婴儿冷冻胚胎成功率高吗