持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第27天,点击查看活动详情
轮廓检测常用于瑕疵检测的某些环节中,在图像处理中有着非常重要的作用。目前Opencv已经提供了瑕疵检测的一些函数,之前cv2.contours()函数就能完成这一系列的操作,目前opencv对该函数做了升级,升级后的函数为cv2.connectedComponentsWithStats(),提供了非常全面的功能,例如可以帮助计算轮廓的周长、面积等。
为了方便直观的查看计算结果,我使用PyQT5制作了一个简单的界面,界面的UI代码如下
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'logUI.ui'
#
# Created by: PyQt5 UI code generator 5.15.6
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(702, 579)
self.horizontalLayoutWidget = QtWidgets.QWidget(Form)
self.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 10, 681, 41))
self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setObjectName("horizontalLayout")
self.pushButton_2 = QtWidgets.QPushButton(self.horizontalLayoutWidget)
self.pushButton_2.setObjectName("pushButton_2")
self.horizontalLayout.addWidget(self.pushButton_2)
self.pushButton = QtWidgets.QPushButton(self.horizontalLayoutWidget)
self.pushButton.setObjectName("pushButton")
self.horizontalLayout.addWidget(self.pushButton)
self.verticalLayoutWidget = QtWidgets.QWidget(Form)
self.verticalLayoutWidget.setGeometry(QtCore.QRect(10, 50, 681, 521))
self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
self.label = QtWidgets.QLabel(self.verticalLayoutWidget)
self.label.setText("")
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
self.retranslateUi(Form)
self.pushButton_2.clicked.connect(Form.openImg) # type: ignore
self.pushButton.clicked.connect(Form.detect) # type: ignore
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.pushButton_2.setText(_translate("Form", "打开图像"))
self.pushButton.setText(_translate("Form", "轮廓检测"))
UI的界面如下
然后就是对两个按钮执行的槽函数操作,首先打开一幅图像,记录图像的绝对地址,然后将图像的绝对地址传递给检测函数,检测函数获取到图像时并对图像进行检测。
此处需要说明的是,对检测按钮并没有进行图像地址的判断,如果不先通过打开图像获取到一副待检测图像,直接点击轮廓检测按钮时会出现报错终止的情况,只需要在轮廓检测按钮的槽函数内加一个if判断,判断self.file_path[0][0]是否为None,如果不为None时进行检测,否则的话不作处理,直接pass。
from logUI import Ui_Form
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
from PyQt5.QtWidgets import QFileDialog
import sys
import cv2
from PyQt5.QtGui import *
import calGrade
import calROIGrade
from PyQt5.QtCore import QRect, Qt
import numpy as np
class MainWindow(QMainWindow, Ui_Form):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent=parent)
self.setupUi(self)
self.file_path = None
def Defect_Marking(self, src):
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) # 二值化
num_labels, labels, stats, centers = cv2.connectedComponentsWithStats(binary, connectivity=8, ltype=cv2.CV_32S)
colors = []
# 生成随机颜色
for i in range(num_labels):
b = np.random.randint(0, 256)
g = np.random.randint(0, 256)
r = np.random.randint(0, 256)
colors.append((b, g, r))
colors[0] = (0, 0, 0)
image = np.copy(src)
dist = []
areas = []
for t in range(1, num_labels, 1):
x, y, w, h, area = stats[t]
cx, cy = centers[t]
cv2.circle(image, (np.int32(cx), np.int32(cy)), 2, (0, 255, 0), 2, 8, 0)
cv2.rectangle(image, (x, y), (x + w, y + h), colors[t], 1, 8, 0)
cv2.putText(image, "num:" + str(t), (x, y), cv2.FONT_HERSHEY_SIMPLEX, .5, (0, 0, 255), 1)
print("label index %d, area of the label : %d" % (t, area))
dist.append([x, y, x + w, y + h])
areas.append(area)
print("total: ", num_labels - 1)
return image
def openImg(self):
try:
self.file_path = QFileDialog.getOpenFileNames(self, "select file", "./", "*.*")
except Exception as e:
print(e)
if self.file_path is not None:
img1 = cv2.imread(self.file_path[0][0])
img_dis = QImage(img1, img1.shape[1], img1.shape[0], QImage.Format_BGR888)
# 加载图片,并设定图片大小
img = QPixmap(img_dis).scaled(int(img1.shape[1]), int(img1.shape[0]))
width = img.width() ##获取图片宽度
height = img.height() ##获取图片高度
if width / self.label.width() >= height / self.label.height(): ##比较图片宽度与label宽度之比和图片高度与label高度之比
ratio = width / self.label.width()
else:
ratio = height / self.label.height()
new_width = int(width / ratio) ##定义新图片的宽和高
new_height = int(height / ratio)
new_img = img.scaled(new_width, new_height) ##调整图片尺寸
# img_dis = QPixmap(img_dis).scaled(int(img.shape[1]), int(img.shape[0]))
self.label.setPixmap(new_img)
def detect(self):
img1 = cv2.imread(self.file_path[0][0])
img = self.Defect_Marking(img1)
img_dis = QImage(img, img.shape[1], img.shape[0], QImage.Format_BGR888)
# 加载图片,并设定图片大小
img = QPixmap(img_dis).scaled(int(img.shape[1]), int(img.shape[0]))
width = img.width() ##获取图片宽度
height = img.height() ##获取图片高度
if width / self.label.width() >= height / self.label.height(): ##比较图片宽度与label宽度之比和图片高度与label高度之比
ratio = width / self.label.width()
else:
ratio = height / self.label.height()
new_width = int(width / ratio) ##定义新图片的宽和高
new_height = int(height / ratio)
new_img = img.scaled(new_width, new_height) ##调整图片尺寸
# img_dis = QPixmap(img_dis).scaled(int(img.shape[1]), int(img.shape[0]))
self.label.setPixmap(new_img)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
首先,我先把实验用的原图放上
然后就是程序的运行结果,打开一幅图像查看原图
然后是执行轮廓检测的结果
为了区分个体,对不同的轮廓用不同的颜色进行标记,最终的检测结果如上图所示。