# 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()
```
### 提取结果
原图:

提取后效果图:

### 存在的问题
**①杂边的处理**:不同于滤除噪点,此处的杂边是由于图像原始图像本身该处成像存在杂项,导致轮廓提取时,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)
```
### 提取结果
原图:

提取后效果图:

### 存在的问题
①多条宽度的检测:目前的代码只支持对框选范围内一个宽度的检测,还无法实现多条宽度同时检测;
②区分线宽和图像边缘宽度:由于图像的轮廓并非严格意义上的线,它占有很小(通常是1-2px)的宽度,但算法在检测的过程中,如果框选不合适,很容易将该轮廓的宽度理解为线宽进行测量。
### 下一步设想
①修改检测算法,实现多线宽的同时提取;
②设置过滤机制,将小于某一临界值的宽度不纳入检测的范围,从而避免将轮廓线宽度检测为线宽;
③对第一步轮廓提取的算法进行进一步优化,是轮廓线更细,杂项轮廓线更少。
思路:从实物图出发直接提取线宽?
## 开源代码
源代码参见[Gitee平台](https://gitee.com/l-wy/challenge-cup)