前言
目標檢測:咱們不只要用算法判斷圖片中是否是貓仍是狗, 還要在圖片中標記出它的位置, 用邊框或紅色方框把貓狗圈起來, 這就是目標檢測問題。其中「定位」的意思是判斷貓狗在圖片中的具體位置。python
目標檢測有兩類任務:單一目標 ,多目標。算法
能力差,電氣專業,又未怎麼深刻研究cv.
因此本文先探討單一目標。
數組
HOG+SVM實現行人檢測
先講解 opencv自帶的行人檢測例子
HOG原理見
計算機視覺:圖像特徵與描述大全 ,有代碼(一篇博文帶你簡單瞭解完圖像特徵提取技術)
app
很少說,上代碼機器學習
import cv2 as cv # 讀取圖像 src = cv.imread("duoren.jpg") cv.imshow("input", src) # HOG + SVM hog = cv.HOGDescriptor() hog.setSVMDetector(cv.HOGDescriptor_getDefaultPeopleDetector()) # Detect people in the image (rects, weights) = hog.detectMultiScale(src,winStride=(4, 4), padding=(8, 8),scale=1.25,useMeanshiftGrouping=False) # 矩形框 for (x, y, w, h) in rects: cv.rectangle(src, (x, y), (x + w, y + h), (0, 255, 0), 2) # 顯示[添加連接描述](https://blog.csdn.net/kobeyu652453/article/details/107382227) cv.imshow("result", src) cv.waitKey(0) cv.destroyAllWindows()

圖像定位實現
python +keras實現圖像分類(入門級例子講解)
opencv進階學習筆記12:輪廓發現和對象測量
ide
目標檢測算法很複雜。
我嘗試用 圖像分類+對象測量 來實現單目標的圖像檢測。
函數
圖像分類 對象測量 很少說了,參考上面給的連接。學習
1讀取圖片並去噪ui
import cv2 as cv image= cv.imread("catdog/dog/dog.77.jpg") image=cv.resize(image,None,fx=0.5,fy=0.5) blurred = cv.GaussianBlur(image, (5, 5), 0) # 去噪
2二值化圖像spa
gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY) ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
3繪製輪廓邊緣
contours, hireachy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
cv2.findContours()函數第一個參數是要檢索的圖片,必須是爲二值圖,即黑白的(不是灰度圖),因此讀取的圖像要先轉成灰度的,再轉成二值圖,
參數講解
contours,hierarchy=cv2.findContours(image,mode,method)
contours:輪廓
hierarchy:圖像的拓撲信息(輪廓層次)(存儲上一個輪廓,父輪廓…)
image:二值圖像
mode:輪廓檢索方式
method:輪廓的近似方法


4求得包含點集最小面積的矩形,這個矩形是能夠有偏轉角度的,能夠與圖像的邊界不平行。
c = sorted(contours, key=cv.contourArea, reverse=True)[0] rect = cv.minAreaRect(c) box = np.int0( cv.boxPoints(rect)) # draw a bounding box arounded the detected barcode and display the image cv.drawContours(image, [box], -1, (0, 255, 0), 3)
講解
double cvContourArea( const CvArr* contour, CvSlice slice=CV_WHOLE_SEQ );
contour:輪廓(頂點的序列或數組)。
slice:感興趣區輪廓部分的起點和終點,默認計算整個輪廓的面積。
c = sorted(contours, key=cv.contourArea, reverse=True)[0]
取出最大的輪廓面積,有些輪廓爲噪聲。
最大輪廓通常狀況下能取到咱們想要的目標物。
minAreaRect函數返回矩形的中心點座標,長寬,旋轉角度[-90,0),當矩形水平或豎直時均返回-90
使用cv2.boxPoints()可獲取該矩形的四個頂點座標。 浮點型數據
np.int0 取整
r=cv2.drawContours(image, contours, contourIdx, color[, thickness])
r:目標圖像
image:原始圖像
contours: 全部的輸入輪廓邊緣數組
contourIdx :須要繪製的邊緣索引,若是所有繪製爲-1。若是有多個目標,能夠繪製第一個目標0,第二個目標1,第三個目標2.。。
color:繪製的顏色,爲BGR格式的SCalar
thickness:可選,繪製的密度,即輪廓的畫筆粗細
5找出四個頂點的x,y座標的最大最小值。矩形框的高=maxY-minY,寬=maxX-minX。
因爲前面的提到的 包含點集最小面積的矩形 有的矩形不與圖像平行,是斜着的,以下圖。咱們調整矩形框。
Xs = [i[0] for i in box] Ys = [i[1] for i in box] x1 = min(Xs) x2 = max(Xs) y1 = min(Ys) y2 = max(Ys) hight = y2 - y1 width = x2 - x1 cropImg = image[y1:y1 + hight, x1:x1 + width] cv.rectangle(image, (x1, y1), (x1 + width, y1 +hight ), (0, 0, 255), 2) # 在原圖上,給輪廓繪製矩形 cv.imshow('result',image)

全部代碼
import cv2 as cv import numpy as np src= cv.imread("dog.16.jpg") src=cv.resize(src,None,fx=0.5,fy=0.5) image=src.copy() #去噪 blurred = cv.GaussianBlur(image, (5, 5), 0) # 去噪 #灰度轉換 gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY) #二值化 ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU) #輪廓發現 contours, hireachy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) #取出最大輪廓 c = sorted(contours, key=cv.contourArea, reverse=True)[0] #找到最大輪廓的最小外接矩形 rect = cv.minAreaRect(c) #取出最小外接矩形的四個頂點 box = np.int0( cv.boxPoints(rect)) #繪製矩形框 Xs = [i[0] for i in box] Ys = [i[1] for i in box] x1 = min(Xs) x2 = max(Xs) y1 = min(Ys) y2 = max(Ys) hight = y2 - y1 width = x2 - x1 cropImg = image[y1:y1 + hight, x1:x1 + width] cv.rectangle(image, (x1, y1), (x1 + width, y1 + hight), (0, 0, 255), 2) # 在原圖上,給輪廓繪製矩形 #顯示 cv.imshow("input image", src) cv.imshow('result', image) cv.waitKey(0) cv.destroyAllWindows()

圖像分類定位實現
我應用圖像分類 加前面提到的定位 結合起來作 單目標的圖像監測。
圖像分類前面給出了連接,這裏再也不給啦,博文太多連接了,會被顯示待審覈。
PYQT 封裝吧。
#!/usr/bin/env python3 # -*- coding: utf-8 -*- # @Author: yudengwu # @Date : 2020/8/1 import sys from PyQt5 import QtWidgets, QtCore, QtGui from PyQt5.QtGui import * from PyQt5.QtWidgets import * from PyQt5.QtCore import * import cv2 import keras from keras .models import load_model import numpy as np import re class picture(QWidget): def __init__(self): super(picture, self).__init__() self.resize(600, 400) self.setWindowTitle("貓狗分類") self.btn = QPushButton() self.btn.setText("打開圖片") self.btn.clicked.connect(self.openimage) self.label = QLabel() self.label.setText('圖片路徑') self.labelimage = QLabel() self.labelimage.setText("顯示圖片") #self.labelimage.setFixedSize(500, 400)#設置尺寸 self.labelimage.setStyleSheet("QLabel{background:white;}" "QLabel{color:rgb(300,300,300,120);font-size:10px;font-weight:bold;font-family:宋體;}" ) #預測按鈕 self.btnclass=QPushButton() self.btnclass.setText('點擊預測分類') self.btnclass.clicked.connect(self.fenlei) self.labelclass=QLabel() self.labelclass.setText('預測類別') self.labelclass.setStyleSheet("font:16pt '楷體';border-width:2px;border-style: inset;border-color:gray") layout1=QVBoxLayout() layout1.addWidget(self.btn) layout1.addWidget(self.label) layout1.addWidget(self.labelimage) layout2 = QVBoxLayout() layout2.addWidget(self.btnclass) layout2.addWidget(self.labelclass) layout=QVBoxLayout() layout.addLayout(layout1) layout.addLayout(layout2) self.setLayout(layout) def openimage(self): imgName, imgType = QFileDialog.getOpenFileName(self, "打開圖片", "", "*.jpg;;*.png;;All Files(*)") #jpg = QtGui.QPixmap(imgName).scaled(self.labelimage.width(), self.label.height())#適應labelimage尺寸,前提是label設置了尺寸 jpg = QtGui.QPixmap(imgName) self.labelimage.setPixmap(jpg) self.label.setText(str(imgName)) def fenlei(self): biaoqian = {'1': '貓', '0': '狗'} path=self.label.text() newName = re.sub('(D:/機器學習/學習草稿/)','', path) #print(newName) img = cv2.imread(str(newName)) img = cv2.resize(img, (100, 100)) # 使尺寸大小同樣 img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img = np.array(img) / 255 img = img.astype(np.float64) img = img.reshape(-1, 100, 100, 1) model = load_model('貓狗分類.h5') predict_y = model.predict(img) pred_y = int(np.round(predict_y)) #print(pred_y) self.labelclass.setText(biaoqian[str(pred_y)]) ########圖像定位 src = cv2.imread(str(newName)) src = cv2.resize(src, None, fx=0.5, fy=0.5) image = src.copy() # 去噪 blurred = cv2.GaussianBlur(image, (5, 5), 0) # 去噪 # 灰度轉換 gray = cv2.cvtColor(blurred, cv2.COLOR_BGR2GRAY) # 二值化 ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) # 輪廓發現 contours, hireachy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 取出最大輪廓 c = sorted(contours, key=cv2.contourArea, reverse=True)[0] # 找到最大輪廓的最小外接矩形 rect = cv2.minAreaRect(c) # 取出最小外接矩形的四個頂點 box = np.int0(cv2.boxPoints(rect)) # 繪製矩形框 Xs = [i[0] for i in box] Ys = [i[1] for i in box] x1 = min(Xs) x2 = max(Xs) y1 = min(Ys) y2 = max(Ys) hight = y2 - y1 width = x2 - x1 cropImg = image[y1:y1 + hight, x1:x1 + width] cv2.rectangle(image, (x1, y1), (x1 + width, y1 + hight), (0, 0, 255), 2) # 在原圖上,給輪廓繪製矩形 #顯示在lableimage上 res = image res = cv2.resize(res, (400, 300), interpolation=cv2.INTER_CUBIC) # 用cv2.resize設置圖片大小 img2 = cv2.cvtColor(res, cv2.COLOR_BGR2RGB) # opencv讀取的bgr格式圖片轉換成rgb格式 _image = QtGui.QImage(img2[:], img2.shape[1], img2.shape[0], img2.shape[1] * 3, QtGui.QImage.Format_RGB888) # pyqt5轉換成本身能放的圖片格式 jpg_out = QtGui.QPixmap(_image) # 轉換成QPixmap self.labelimage.setPixmap(jpg_out) # 設置圖片顯示 cv2.waitKey() cv2.destroyAllWindows() if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) my = picture() my.show() sys.exit(app.exec_())
說明:
model = load_model(‘貓狗分類.h5’)
導入訓練好的分類模型
在PYQT中顯示opencv圖 核心代碼
def setImage(self): img = cv2.imread('test.jpg') #opencv讀取圖片 img2 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) #opencv讀取的bgr格式圖片轉換成rgb格式 _image = QtGui.QImage(img2[:], img2.shape[1], img2.shape[0], img2.shape[1] * 3, QtGui.QImage.Format_RGB888) #pyqt5轉換成本身能放的圖片格式 jpg_out = QtGui.QPixmap(_image).scaled(self.imgLabel.width(), self.imgLabel.height()) #設置圖片大小 self.imgLabel.setPixmap(jpg_out) #設置圖片顯示
結果演示


本文給出的方法不是純粹的目標檢測算法。定位有的圖有所缺陷。
只是圖像分類+對象測量 來實現單一目標檢測功能
等我有時間研究下目標檢測算法後,再來寫博文。
電氣專業的計算機萌新,寫博文不容易,若是你以爲本文對你有用,請點個贊支持下,謝謝。