# Challenge-Cup **Repository Path**: l-wy/challenge-cup ## Basic Information - **Project Name**: Challenge-Cup - **Description**: “挑战杯”光刻胶图像处理项目 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2021-06-02 - **Last Updated**: 2022-01-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Challenge-Cup “挑战杯” 光刻成像分析 轮廓提取与线宽提取部分 ## 轮廓提取 轮廓的定义? ### 技术路线 对于图像轮廓边缘的提取,采用John F. Canny提出Canny边缘检测算子。相比Sobel、Prewitt等算子,Canny算法更为优异,它能够基于边缘梯度方向进行非极大值抑制,同时对双阈值的滞后阈值进行处理。 Canny算法能够保证所有边缘都应被找到,且没有伪响应。同时,图像的边缘能被很好地定位,已定位的边缘尽可能接近真实边缘。当图像中仅存一个单一边缘点的位置,Canny算法能够保证检测器不指出多个像素边缘。从表面效果上来讲,Canny算法是对Sobel、Prewitt等算子效果的进一步细化和更加准确的定位。 实现Canny算法的步骤如下: - **Step1**:对输入图像进行高斯平滑,降低错误率。 - **Step2**:用一阶偏导的有限差分来计算梯度的幅值和方向。 - **Step3**:根据梯度方向,对梯度幅值进行非极大值抑制。本质上是对Sobel、Prewitt等算子结果的进一步细化。 - **Step4**:用双阈值处理和连接边缘。 ### 代码实现 基于[OpenCV库](https://opencv.org/),`Step1`中对应的高斯模糊可以通过`cv2.GaussianBlur()` 方法实现,这一步的目的是滤除图像中的噪点,使图像更平滑。 `cv2.threshold()` 方法能够设置图像阈值,阈值影响梯度运算的效果。 `cv2.morphologyEx()` 方法能够得到梯度处理的结果。 `cv2.Canny(img, weight, height)` 能够对原图weight×height部分进行Canny轮廓提取 ```python import cv2 import numpy as np # 读取图像文件 original_img = cv2.imread(r'D:\challenge-cup\challenge-cup\RealPics\1.png', 0) # GaussianBlur:高斯模糊 img1 = cv2.GaussianBlur(original_img,(3,3),0) cv2.imshow("GaussianBlur", img1) canny = cv2.Canny(img1, 50, 150) # 形态学:边缘检测 # 设定红色通道阈值210(阈值影响梯度运算效果) _,Thr_img = cv2.threshold(original_img,210,255,cv2.THRESH_BINARY) # 定义矩形结构元素 kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5)) # 梯度 gradient = cv2.morphologyEx(Thr_img, cv2.MORPH_GRADIENT, kernel) cv2.imshow("original_img", original_img) cv2.imshow("gradient", gradient) cv2.imshow('Canny', canny) # 将结果保存在 \result 文件夹下 cv2.imwrite(r'D:\challenge-cup\challenge-cup\result\canny.png',canny) cv2.waitKey(0) cv2.destroyAllWindows() ``` ### 提取结果 原图: ![5](.\RealPics\5.png) 提取后效果图: ![canny](.\result\canny2.png) ### 存在的问题 **①杂边的处理**:不同于滤除噪点,此处的杂边是由于图像原始图像本身该处成像存在杂项,导致轮廓提取时,Canny算法将其机械地认为是光刻图片的一部分,也将杂项的轮廓纳入轮廓提取的范畴; **②弱强度边缘部分的提取**:由于成像质量有限,部分轮成像强度较弱。人可以通过合理外推,推理得到该边缘的位置,但Canny算法将该部分直接忽略掉了,从而造成轮廓缺失。 ### 下一步设想 ①引入深度学习模型,尝试对识别的内容进行图像理解和分析,将明显的杂边剔除掉,同时,通过合理地推测,将强度不够的边缘部分补全。 ②希望能够得到成像效果更好的光刻胶图像。 ## 线宽提取 ### 技术路线 基于[OpenCV库](https://opencv.org/),在完成轮廓提取后的图像中,使用`cv2.boundingRect()`等方法,提取图像宽度(像素值) - 读取图片 - 截取目标区域 - 二值化处理 - 边缘检测、图片反色 - 边缘检测,框出物体的轮廓 - 绘制直线 - 图片上添加宽度大小 ### 代码实现 ```python import cv2 import numpy as np import imutils #读取图片 img = cv2.imread(r'D:\challenge-cup\challenge-cup\result\canny.png') cv2.imshow("Original_img",img) #截取目标区域 img = imutils.resize(img, width=img.shape[1]) roi = cv2.selectROI(windowName="image_to_measure", img=img, showCrosshair=False, fromCenter=False) dx, dy, dw, dh = roi recimg = img[dy:dy+dh,dx:dx+dw] #二值化处理 ret, th = cv2.threshold(recimg, 80, 255, cv2.THRESH_BINARY_INV) cv2.imshow("img_2value",th) # 边缘检测、图片反色 img1 = cv2.Canny(recimg, 100, 200) img1 = 255 - cv2.cvtColor(img1, cv2.COLOR_BGR2RGB) img2 = cv2.cvtColor(img1, cv2.COLOR_RGB2GRAY) img2 = cv2.cvtColor(255 - th, cv2.COLOR_RGB2GRAY) cv2.imshow("edge",img2) # 边缘检测,框出物体的轮廓 contours, hierarchy = cv2.findContours(img2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnt = contours[0] x, y, w, h = cv2.boundingRect(cnt) # 绘制直线 cv2.line(img1, (x, y), (x, y+h), (0,255,0), 3, 5) cv2.line(img1, (x + w, y), (x + w, y+h), (0, 255, 0), 3, 5) img[dy:dy+dh, dx:dx+dw] = img1 #图片上添加宽度大小 cv2.putText(img,'width:'+str(w),(10,30),cv2.FONT_HERSHEY_COMPLEX,1,(0,255,0),1) cv2.imshow('width_result',img) cv2.waitKey(0) ``` ### 提取结果 原图: ![original](.\result\original.jpg) 提取后效果图: ![width_result](.\result\width_result.jpg) ### 存在的问题 ①多条宽度的检测:目前的代码只支持对框选范围内一个宽度的检测,还无法实现多条宽度同时检测; ②区分线宽和图像边缘宽度:由于图像的轮廓并非严格意义上的线,它占有很小(通常是1-2px)的宽度,但算法在检测的过程中,如果框选不合适,很容易将该轮廓的宽度理解为线宽进行测量。 ### 下一步设想 ①修改检测算法,实现多线宽的同时提取; ②设置过滤机制,将小于某一临界值的宽度不纳入检测的范围,从而避免将轮廓线宽度检测为线宽; ③对第一步轮廓提取的算法进行进一步优化,是轮廓线更细,杂项轮廓线更少。 思路:从实物图出发直接提取线宽? ## 开源代码 源代码参见[Gitee平台](https://gitee.com/l-wy/challenge-cup)