OpenCV 버전: 4.6.0.66
알고리즘 구현 아이디어:
- 색상 인식(빨간색)
- 형태학적 노이즈 제거
- 윤곽 감지
- 폴리곤 피팅
- 원근 교정
암호:
import cv2
import numpy as np
# 可视化
def img_show(name, img):
cv2.namedWindow(name, 0)
cv2.resizeWindow(name, 1000, 500)
cv2.imshow(name, img)
cv2.waitKey(0)
def color_warped(path):
img = cv2.imread(path)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 颜色识别(红色),过滤红色区域
lower_red1 = np.array([0, 43, 46]) # 红色阈值下界
higher_red1 = np.array([10, 255, 255]) # 红色阈值上界
mask_red1 = cv2.inRange(hsv, lower_red1, higher_red1)
lower_red2 = np.array([156, 43, 46]) # 红色阈值下界
higher_red2 = np.array([180, 255, 255]) # 红色阈值上界
mask_red2 = cv2.inRange(hsv, lower_red2, higher_red2)
mask_red = cv2.add(mask_red1, mask_red2) # 拼接过滤后的mask
img_show('mask_red', mask_red)
# 形态学去噪,cv2.MORPH_OPEN先腐蚀再膨胀,cv2.MORPH_CLOSE先膨胀再腐蚀
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
mask_red = cv2.morphologyEx(mask_red, cv2.MORPH_OPEN, kernel, iterations=1)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
mask_red = cv2.morphologyEx(mask_red, cv2.MORPH_CLOSE, kernel, iterations=3)
img_show('mask_red', mask_red)
# 轮廓检测,找出线条的轮廓
draw_cnt = img.copy()
cnts = cv2.findContours(mask_red, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]
cv2.drawContours(draw_cnt, cnts, -1, (0, 255, 0), 2)
img_show('draw_cnt', draw_cnt)
# 四边形拟合,找到相应的的顶点
draw_approx = img.copy()
point1, point2 = list(), list()
for cnt in cnts:
for epsilon in range(50):
approx = cv2.approxPolyDP(cnt, epsilon, True)
if len(approx) == 4:
break
cv2.polylines(draw_approx, [approx], True, (0, 0, 255), 2) # 绘制边
for i in approx:
cv2.circle(draw_approx, i[0], 6, (0, 0, 0), -1) # 绘制顶点
approx = [i[0] for i in approx.tolist()]
approx = sorted(approx, key=lambda k: k[1], reverse=False) # 按y坐标排序,升序
point1.extend(approx[:2]) # 存放上顶点坐标
point2.extend(approx[2:]) # 存放下顶点坐标
point1.sort(key=lambda k: k[0], reverse=False) # 按x坐标排序,升序
point2.sort(key=lambda k: k[0], reverse=False)
img_show('draw_approx', draw_approx)
# 透视矫正目标区域
w, h = 900, 300
rect = [point1[0], point1[-1], point2[-1], point2[0]] # 顺序为第一个四边形的左上,第四个四边形的右上,第四个四边形的右下,第一个四边形的左下
pts1 = np.array(rect, dtype="float32")
pts2 = np.array([rect[0], [rect[0][0] + w, rect[0][1]],
[rect[0][0] + w, rect[0][1] + h], [rect[0][0], rect[0][1] + h]], dtype="float32")
M = cv2.getPerspectiveTransform(pts1, pts2) # 变换矩阵
img_warped = cv2.warpPerspective(img, M, (1500, 500)) # 透视变换
img_show('img_warped1', img_warped)
img_warped = img_warped[rect[0][1]: rect[0][1] + h, rect[0][0]: rect[0][0] + w] # 抠出变换后的区域
img_show('img_warped2', img_warped)
if __name__ == '__main__':
path = 'data/picture/18.jpg'
color_warped(path)
원본 이미지:
색상 인식(빨간색)
img = cv2.imread(path)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
색상 인식에 사용되는 채널은 HSV 채널입니다. HSV 채널을 사용하여 색상을 식별하는 것이 BGR 채널을 사용하는 것보다 쉽게 구분할 수 있습니다. H는 색조 (hue, 색조, 값: 0-180), S는 채도 (채도, 색상 순도, 값: 0-255), V는 값 (밝기, 값: 0-255), 자세히 표시: HSV 색상 공간 . 각 색상의 값 범위는 다음과 같습니다.
빨간색 에 대해 두 가지 값 범위가 있음 을 알 수 있으며 이 두 범위는 대부분의 경우 보완적일 뿐이며 실제 상황에 따라 조정할 수 있습니다.
# 颜色识别(红色),过滤红色区域
lower_red1 = np.array([0, 43, 46]) # 红色阈值下界
higher_red1 = np.array([10, 255, 255]) # 红色阈值上界
mask_red1 = cv2.inRange(hsv, lower_red1, higher_red1)
lower_red2 = np.array([156, 43, 46]) # 红色阈值下界
higher_red2 = np.array([180, 255, 255]) # 红色阈值上界
mask_red2 = cv2.inRange(hsv, lower_red2, higher_red2)
mask_red = cv2.add(mask_red1, mask_red2) # 拼接过滤后的mask
필터링된 바이너리 이미지는 다음과 같습니다.
형태학적 노이즈 제거
# 形态学去噪,cv2.MORPH_OPEN先腐蚀再膨胀,cv2.MORPH_CLOSE先膨胀再腐蚀
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
mask_red = cv2.morphologyEx(mask_red, cv2.MORPH_OPEN, kernel, iterations=1)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
mask_red = cv2.morphologyEx(mask_red, cv2.MORPH_CLOSE, kernel, iterations=3)
색상 인식은 노이즈 의 일부를 함께 인식하는 경우가 있는데 , 이때 노이즈 제거를 위해 모폴로지를 사용할 수 있습니다. 형태학적 노이즈 제거를 위해 cv2.morphologyEx를 사용하기 전에 컨볼루션 커널 의 모양 과 크기를 cv2.getStruturingElement 로 정의해야 합니다 .
cv2.getStruturingElement(shape, ksize)의 공통 매개변수 는 다음과 같습니다.
- shape: 커널의 모양, cv2.MORPH_RECT ( 사각형 ), cv2.MORPH_CROSS ( 십자형 ), cv2.MORPH_ELLIPSE ( 타원형 )
- ksize: (너비, 높이) 형식의 코어 크기
cv2.morphologyEx(src, op, kernel, iterations)의 공통 매개변수 는 다음과 같습니다.
- src: 입력 이미지
- op: 형태학적 연산의 유형, cv2.MORPH_ERODE ( 침식 ), cv2.MORPH_DILATE ( 팽창 ), cv2.MORPH_OPEN ( 열기 연산 ), cv2.MORPH_CLOSE ( 닫기 연산 ), cv2.MORPH_GRADIENT ( 그래디언트 연산 ), cv2.MORPH_TOPHAT ( Top hat 연산 ), cv2.MORPH_BLACKHAT ( 검은 모자 연산 ), 자세한 내용 보기: Morphological 연산
- 커널: 형태학적 연산을 위한 컨볼루션 커널
- iterations: 형태학적 연산 반복 횟수, 기본값은 1
효과는 다음과 같습니다.
윤곽 감지
# 轮廓检测,找出线条的轮廓
draw_cnt = img.copy()
cnts = cv2.findContours(mask_red, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]
cv2.drawContours(draw_cnt, cnts, -1, (0, 255, 0), 2)
cv2.findContours(image, mode, method)를 사용하여 윤곽선을 감지합니다. 공통 매개변수는 다음과 같습니다.
- 이미지: 이진 이미지
- mode: 윤곽선 검색 모드
cv2.RETR_EXTERNAL 외부 윤곽만 감지 cv2.RETR_LIST 감지된 윤곽선은 계층적 관계를 설정하지 않습니다. cv2.RETR_CCOMP 2단계 등고선이 설정되며, 상위 레이어는 외부 경계이고 내부 레이어는 내부 구멍의 경계 정보입니다. 내부 구멍에 연결된 다른 객체가 있으면 이 객체의 경계도 최상위 레이어에 있습니다. cv2.RETR_TREE 계층적 트리 구조의 개요 작성
- method: 윤곽선의 근사화 방법
cv2.CHAIN_APPROX_NONE 모든 윤곽점을 저장하고 인접한 두 점 사이의 픽셀 위치 차이는 1을 초과하지 않습니다. cv2.CHAIN_APPROX_SIMPLE 가로 방향, 세로 방향, 대각선 방향의 요소를 압축하고 방향의 끝 좌표만 유지
cv2.drawContours를 사용하여 윤곽선을 그립니다. 효과는 다음과 같습니다.
대략적인 다각형
# 四边形拟合,找到相应的的顶点
draw_approx = img.copy()
point1, point2 = list(), list()
for cnt in cnts:
for epsilon in range(50):
approx = cv2.approxPolyDP(cnt, epsilon, True)
if len(approx) == 4:
break
cv2.polylines(draw_approx, [approx], True, (0, 0, 255), 2) # 绘制边
for i in approx:
cv2.circle(draw_approx, i[0], 6, (0, 0, 0), -1) # 绘制顶点
cv2.approxPolyDP(curve, epsilon, closed)를 사용하여 다각형을 근사화합니다. 공통 매개변수는 다음과 같습니다.
- 곡선: 입력된 2차원 점 집합 의 배열
- 엡실론: 대략적인 결과의 정밀도 . 이것은 원래 곡선과 그 근사치 사이의 최대 거리입니다. 엡실론이 작을수록 근사 결과의 폴리라인 모양이 곡선에 더 가깝습니다. 자세한 내용은 대략적인 다각형을 참조하십시오.
- 닫힘: True 또는 False . True는 근사 곡선이 닫혀 있음을 나타내고 (첫 번째 정점이 마지막 정점에 연결됨), False는 근사 곡선이 닫히지 않음 을 나타냅니다.
cv2.approxPolyDP는 대략적인 다각형의 꼭짓점 좌표를 반환합니다 . 여기서 엡실론 정밀도는 범위 내의 값으로 순회합니다 . 반환되는 꼭지점 좌표 의 수가 4 일 때 사변형 입니다 .
각 윤곽선에 대해 사변형 피팅을 수행하고 cv2.polylines 및 cv2.circle을 사용하여 가장자리 와 정점을 각각 그립니다 . 효과는 다음과 같습니다.
사각형이 맞춰진 후 각 사각형의 정점이 정렬 됩니다 .
원근 교정
# 透视矫正目标区域
w, h = 900, 300
rect = [point1[0], point1[-1], point2[-1], point2[0]] # 顺序为第一个四边形的左上,第四个四边形的右上,第四个四边形的右下,第一个四边形的左下
pts1 = np.array(rect, dtype="float32")
pts2 = np.array([rect[0], [rect[0][0] + w, rect[0][1]],
[rect[0][0] + w, rect[0][1] + h], [rect[0][0], rect[0][1] + h]], dtype="float32")
M = cv2.getPerspectiveTransform(pts1, pts2) # 变换矩阵
img_warped = cv2.warpPerspective(img, M, (1500, 500)) # 透视变换
원근 변환 에 cv2.warpPerspective를 사용 하기 전에 변환 행렬을 cv2.getPerspectiveTransform 으로 가져와야 합니다 .
cv2.getPerspectiveTransform(src, dst)의 공통 매개변수는 다음과 같습니다.
- src: 변환 전 사변형 이미지 의 꼭지점 좌표 ( 배열 ) . 여기서 세 점은 동일 선상에 있지 않습니다.
- dst: 변환된 이미지 사변형 의 꼭짓점 좌표 ( 배열 ) , 여기서 임의의 세 점이 동일선상에 있지 않음
여기에 변환 전 사변형의 정점 좌표인 첫 번째 사변형의 왼쪽 위 좌표 , 네 번째 사변형의 오른쪽 위 좌표 , 네 번째 사변형의 오른쪽 아래 좌표 , 첫 번째 사변형 의 왼쪽 아래 좌표를 입력합니다. 사변형; 변환된 사변형의 정점 입력 좌표는 첫 번째 사변형의 왼쪽 위 좌표의 너비와 높이를 확장합니다 .
cv2.getPerspectiveTransform(src, M, dsize)의 공통 매개변수 는 다음과 같습니다.
- src: 입력 이미지
- M: 변환 행렬
- dsize: 출력 이미지 크기
변환 효과는 다음과 같습니다.
img_warped = img_warped[rect[0][1]: rect[0][1] + h, rect[0][0]: rect[0][0] + w] # 抠出变换后的区域
변환된 영역을 잘라내면 효과는 다음과 같습니다.
참조 링크
RGB, HSV 및 HSL 색 공간을 빠르게 배울 수 있는 3분 - Programmer Sought
Chapter 8 형태론적 연산 -- 8.3 커널 함수 cv2.getStruturingElement()
Python +OpenCV CH9: 형태학 연산(morphologyEx 확장자)_liguoxin1990's blog-CSDN 블로그
Python OpenCV approxPolyDP() 함수
다각형 근사 cv2.approxPolyDP 및 Douglas-Peucker algorithm_00000cj's blog-CSDN blog_Polygon 근사 알고리즘