是在檢測圖片的基礎上進行加工的 詳情可看opencv圖片傾斜度檢(一)對圖片進行檢測
打開攝像頭進行實時檢測矩形輪廓,實時畫出坐標軸坐標點和傾斜度,并且具有保存圖片和利用plot單純畫出矩形的功能
直接上全部代碼 注釋已經比較詳細了
如下:
from matplotlib.cm import register_cmap
import matplotlib.pyplot as plt
import cv2
import numpy as np
import imutils
import time
from scipy.spatial import distance as dist
#呼叫攝像頭 函式
def read_usb_capture():
# 選擇攝像頭的編號
cap = cv2.VideoCapture(1, cv2.CAP_DSHOW)# 0是筆記本自帶攝像頭
# 添加這句是可以用滑鼠拖動彈出的表單
cv2.namedWindow('video', cv2.WINDOW_NORMAL)
while (cap.isOpened()):#回圈
ret, frame = cap.read()#read放回2個值,第一個是True和False 是否打開 第二個是傳入影像
lunkuo(frame)#進行輪廓檢測
cv2.imshow('video', frame)#顯示出來
k = cv2.waitKey(1) & 0xFF#監聽鍵盤
if k == ord('s'):# 保存鍵
cv2.imwrite("1.jpg", frame)
img = cv2.imread('1.jpg')
cv2.imshow('img',img)
# 按下'q'就退出
if k == ord('q'):#退出鍵
break
# 釋放畫面
cap.release()
cv2.destroyAllWindows()
def midpoint(ptA, ptB):#計算坐標中點函式
return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)
def show(img): # 顯示圖片函式
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
def lunkuo(img):#檢測輪廓
start = time.time()#計算檢測時間
img1_ = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 轉換為灰度
img_ = cv2.GaussianBlur(img1_, (5, 5), 0) # 高斯濾波去噪點
img__ = cv2.Canny(img_, 75, 200) # Canny邊緣檢測
img__ = cv2.dilate(img__, None, iterations=1)#擴張
img__ = cv2.erode(img__, None, iterations=1)#腐蝕
# 輪廓檢測
cnts = cv2.findContours(img__.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) # 檢測出所有輪廓
cnts = cnts[1] if imutils.is_cv3() else cnts[0] # opencv4寫法
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:] # 排序得到前x個輪廓 可以根據圖片自己設定
#定義全域變數
global screenCnt,box,rangle
box = 0
rangle = 0
# 我的攝像頭解析度為640*480 在攝像頭中框出最合適檢測的地方
cv2.line(img, (595, 45), (595, 435),
(255, 0, 255), 1)
cv2.line(img, (45, 435), (595, 435),
(255, 0, 255), 1)
cv2.line(img, (45, 45), (45, 435),
(255, 0, 255), 1)
cv2.line(img, (45, 45), (595, 45),
(255, 0, 255), 1)
cv2.line(img, (45, 45), (595, 45),
(255, 0, 255), 1)
cv2.circle(img, (45, 45), 2, (255, 0, 0), -1)#中心點
cv2.putText(img, "(0,0)",
(45, 435), cv2.FONT_HERSHEY_SIMPLEX,
0.5, (0, 244, 245), 2)#攝像頭的坐標軸原點是在左上角 自己設定坐標軸原點并顯示
#遍歷輪廓
for c in cnts:
# 計算輪廓近似
peri = cv2.arcLength(c, True)
# C表示輸入的點集
# epsilon表示從原始輪廓到近似輪廓的最大距離,它是一個準確度引數
# True表示封閉的
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
# 4個點的時候就拿出來 因為物品是矩陣形狀
if len(approx) == 4:
screenCnt = approx # 保存下來
rangle = cv2.minAreaRect(screenCnt)[2] # minAreaRect()函式回傳角度 是最低的邊到x水平坐標軸的角度
box = cv2.cv.BoxPoints(cv2.minAreaRect(screenCnt)) if imutils.is_cv2() else cv2.boxPoints(
cv2.minAreaRect(screenCnt))#得到四個最小矩陣的坐標點
cv2.drawContours(img, [box.astype("int")], -1, (0, 255, 0), 2)#在圖中畫出來
box = np.array(box, dtype="int")#轉換型別
(tl, tr, br, bl) = box#得到左上 右上 左下 右下的坐標點
#計算中點
(tltrX, tltrY) = midpoint(tl, tr)
(blbrX, blbrY) = midpoint(bl, br)
(tlblX, tlblY) = midpoint(tl, bl)
(trbrX, trbrY) = midpoint(tr, br)
#歐幾里得度量
dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
#固定攝像頭及解析度時 要想測出所測物品的長度 需要參照物 先使用已知寬度的矩形進行測量 得到 像素寬/實際寬 = 每寬多少像素 并保存下來
# print('DB:',dB)
# i = 1
# if i == 1:
# pixelsPerMetric = dB / 3.4
# print(pixelsPerMetric)
# i += 1
pixelsPerMetric = 35.15#得到的比率
#解析度除以比率可以得到攝像頭測的實際范圍長度
# print('H:',640/pixelsPerMetric)
# print('w:',480/pixelsPerMetric)
if pixelsPerMetric != 0:#防止出現檢測中沒有實物得不到比例而發生除以0的錯誤
#實際寬度
dimA = dA / pixelsPerMetric
dimB = dB / pixelsPerMetric
#顯示寬度
cv2.putText(img, "{:.1f}cm".format(dimB),
(int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,
0.65, (225, 190, 0), 2)
cv2.putText(img, "{:.1f}cm".format(dimA),
(int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,
0.65, (225, 190, 0), 2)
#顯示角度 此角度是經過變換后的 是我定義的坐標軸的矩形的最低點與x軸的夾角
cv2.putText(img, "r:{:.1f}".format(90 - rangle),
(int(tltrX + 20), int(tltrY + 20)), cv2.FONT_HERSHEY_SIMPLEX,
0.65, (225, 190, 0), 2)
#畫出點的坐標的直線并顯示坐標點資料 容易觀察夾角的位置 并且可以利用坐標計算夾角
cv2.line(img, (int(bl[0]), int(bl[1])), (int(bl[0]), 435),
(0, 244, 245), 1)
cv2.putText(img, "({},{})".format(bl[0], 640 - bl[1]),
(int(bl[0] - 20), 415), cv2.FONT_HERSHEY_SIMPLEX,
0.4, (225, 190, 0), 1)
cv2.line(img, (int(br[0]), int(br[1])), (int(br[0]), 435),
(0, 244, 245), 1)
cv2.putText(img, "({},{})".format(br[0], 640 - br[1]),
(int(br[0]), 435), cv2.FONT_HERSHEY_SIMPLEX,
0.4, (225, 190, 0), 1)
cv2.line(img, (int(bl[0]), int(bl[1])), (int(595), int(bl[1])),
(0, 244, 245), 1)
end = time.time()#時間
print("輪廓檢測所用時間:{:.3f}ms".format((end - start) * 1000))
#得到坐標點在plot上進行繪畫以及保存
# x = [-tr[0], -tl[0], -br[0], -bl[0], -tr[0]]
# y = [tr[1], tl[1], br[1], bl[1], tr[1]]
# plt.plot(x, y)
# plt.axhline(y=min(y), c="r", ls="--", lw=2)
# plt.title("rangel = {}".format(rangle))
# for a, b in zip(x, y):
# plt.text(a, b, (a, b), ha='center', va='bottom', fontsize=10)
#plt.savefig('D:\zuobiao.png')
return img
read_usb_capture()#開始
代碼結果如下:

新增一個按下d鍵打開輪廓的坐標圖功能
將畫圖部分整合成函式,使用全域變數作為觸發標志
代碼如下:
from matplotlib.cm import register_cmap
import matplotlib.pyplot as plt
import cv2
import numpy as np
import imutils
import time
from scipy.spatial import distance as dist
from PIL import Image
global d#全域變數拿來判斷是否按下d
d = 0
#呼叫攝像頭 函式
def read_usb_capture():
# 選擇攝像頭的編號
cap = cv2.VideoCapture(1, cv2.CAP_DSHOW)# 0是筆記本自帶攝像頭
# 添加這句是可以用滑鼠拖動彈出的表單
cv2.namedWindow('video', cv2.WINDOW_AUTOSIZE)
cv2.resizeWindow("video", 640, 480) # 設定長和寬
while (cap.isOpened()):#回圈
ret, frame = cap.read()#read放回2個值,第一個是True和False 是否打開 第二個是傳入影像
lunkuo(frame)#進行輪廓檢測
cv2.imshow('video', frame)#顯示出來
k = cv2.waitKey(1) & 0xFF # 監聽鍵盤
if k == ord('s'):# 保存鍵
cv2.imwrite("1.jpg", frame)
img = cv2.imread('1.jpg')
cv2.imshow('img',img)
# 按下'q'就退出
if k == ord('q'):#退出鍵
break
if k == ord('d'):
global d
d = 1#作為畫圖觸發條件
# 釋放畫面
cap.release()
cv2.destroyAllWindows()
def plot(tl,tr,bl,br):#畫圖并且展示函式
# 得到坐標點在plot上進行繪畫以及保存
x = [tl[0], tr[0], br[0], bl[0], tl[0]]
y = [640 - tl[1], 640 - tr[1], 640 - br[1], 640 - bl[1], 640 - tl[1]]
plt.plot(x, y)
plt.axhline(y=min(y), c="r", ls="--", lw=2)
plt.title("rangel = {}".format(90 - rangle))
plt.axis("equal")
for a, b in zip(x, y):
plt.text(a, b, (a, b), ha='center', va='bottom', fontsize=10)
plt.savefig('zuobiao.png')#保存下來
plt.clf()#清除
plt.cla()
fp = open('zuobiao.png', 'rb')
img = Image.open(fp)#打開并且展示
img.show()
def midpoint(ptA, ptB):#計算坐標中點函式
return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)
def lunkuo(img):#檢測輪廓
start = time.time()#計算檢測時間
img1_ = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 轉換為灰度
img_ = cv2.GaussianBlur(img1_, (5, 5), 0) # 高斯濾波去噪點
img__ = cv2.Canny(img_, 75, 200) # Canny邊緣檢測
img__ = cv2.dilate(img__, None, iterations=1)#擴張
img__ = cv2.erode(img__, None, iterations=1)#腐蝕
# 輪廓檢測
cnts = cv2.findContours(img__.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) # 檢測出所有輪廓
cnts = cnts[1] if imutils.is_cv3() else cnts[0] # opencv4寫法
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:] # 排序得到前x個輪廓 可以根據圖片自己設定
#定義全域變數
global screenCnt,box,rangle
box = 0
rangle = 0
# 我的攝像頭解析度為640*480 在攝像頭中框出最合適檢測的地方
cv2.line(img, (595, 45), (595, 435),
(255, 0, 255), 1)
cv2.line(img, (45, 435), (595, 435),
(255, 0, 255), 1)
cv2.line(img, (45, 45), (45, 435),
(255, 0, 255), 1)
cv2.line(img, (45, 45), (595, 45),
(255, 0, 255), 1)
cv2.line(img, (45, 45), (595, 45),
(255, 0, 255), 1)
cv2.circle(img, (45, 45), 2, (255, 0, 0), -1)#中心點
cv2.putText(img, "(0,0)",
(45, 435), cv2.FONT_HERSHEY_SIMPLEX,
0.5, (0, 244, 245), 2)#攝像頭的坐標軸原點是在左上角 自己設定坐標軸原點并顯示
#遍歷輪廓
for c in cnts:
# 計算輪廓近似
peri = cv2.arcLength(c, True)
# C表示輸入的點集
# epsilon表示從原始輪廓到近似輪廓的最大距離,它是一個準確度引數
# True表示封閉的
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
# 4個點的時候就拿出來 因為物品是矩陣形狀
if len(approx) == 4:
screenCnt = approx # 保存下來
rangle = cv2.minAreaRect(screenCnt)[2] # minAreaRect()函式回傳角度 是最低的邊到x水平坐標軸的角度
box = cv2.cv.BoxPoints(cv2.minAreaRect(screenCnt)) if imutils.is_cv2() else cv2.boxPoints(
cv2.minAreaRect(screenCnt))#得到四個最小矩陣的坐標點
cv2.drawContours(img, [box.astype("int")], -1, (0, 255, 0), 2)#在圖中畫出來
box = np.array(box, dtype="int")#轉換型別
(tl, tr, br, bl) = box#得到左上 右上 左下 右下的坐標點
#計算中點
(tltrX, tltrY) = midpoint(tl, tr)
(blbrX, blbrY) = midpoint(bl, br)
(tlblX, tlblY) = midpoint(tl, bl)
(trbrX, trbrY) = midpoint(tr, br)
#歐幾里得度量
dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
#固定攝像頭及解析度時 要想測出所測物品的長度 需要參照物 先使用已知寬度的矩形進行測量 得到 像素寬/實際寬 = 每寬多少像素 并保存下來
# print('DB:',dB)
# i = 1
# if i == 1:
# pixelsPerMetric = dB / 3.4
# print(pixelsPerMetric)
# i += 1
pixelsPerMetric = 35.15#得到的比率
#解析度除以比率可以得到攝像頭測的實際范圍長度
# print('H:',640/pixelsPerMetric)
# print('w:',480/pixelsPerMetric)
if pixelsPerMetric != 0:#防止出現檢測中沒有實物得不到比例而發生除以0的錯誤
#實際寬度
dimA = dA / pixelsPerMetric
dimB = dB / pixelsPerMetric
#顯示寬度
cv2.putText(img, "{:.1f}cm".format(dimB),
(int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,
0.65, (225, 190, 0), 2)
cv2.putText(img, "{:.1f}cm".format(dimA),
(int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,
0.65, (225, 190, 0), 2)
#顯示角度 此角度是經過變換后的 是我定義的坐標軸的矩形的最低點與x軸的夾角
cv2.putText(img, "r:{:.1f}".format(90 - rangle),
(int(tltrX + 20), int(tltrY + 20)), cv2.FONT_HERSHEY_SIMPLEX,
0.65, (225, 190, 0), 2)
#畫出點的坐標的直線并顯示坐標點資料 容易觀察夾角的位置 并且可以利用坐標計算夾角
cv2.line(img, (int(bl[0]), int(bl[1])), (int(bl[0]), 435),
(0, 244, 245), 1)
cv2.putText(img, "({},{})".format(bl[0], 640 - bl[1]),
(int(bl[0] - 20), 415), cv2.FONT_HERSHEY_SIMPLEX,
0.4, (225, 190, 0), 1)
cv2.line(img, (int(br[0]), int(br[1])), (int(br[0]), 435),
(0, 244, 245), 1)
cv2.putText(img, "({},{})".format(br[0], 640 - br[1]),
(int(br[0]), 435), cv2.FONT_HERSHEY_SIMPLEX,
0.4, (225, 190, 0), 1)
cv2.line(img, (int(bl[0]), int(bl[1])), (int(595), int(bl[1])),
(0, 244, 245), 1)
end = time.time()#時間
print("輪廓檢測所用時間:{:.3f}ms".format((end - start) * 1000))
global d
if d == 1:#觸發條件
plot(tl, tr, bl, br)#畫圖
d = 0#清除標志
return img
read_usb_capture()#開始
按下 d 結果如下:
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/292448.html
標籤:其他
下一篇:語音識別 平常筆記
