728x90
2021/02/24 - [기록 note] - 2021-02-24(OpenCV_6)
### threshold
import sys
import numpy as np
import cv2
src = cv2.imread('cells.png', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
sys.exit()
# 임계값이 왜 리턴 될까? 자동으로 임계값을 결정하는 알고리즘에서 필요하게된다
#수동으로 임계값 결정할땐 리턴되는 임계값을 받을 필요가 없다
#dst1은 모든 세포를 검출
_,dst1= cv2.threshold(src, 210,255, cv2.THRESH_BINARY)
#dst2는 세포중에서 염색된 것만 검출
_,dst2= cv2.threshold(src, 100,255, cv2.THRESH_BINARY)
cv2.imshow('src', src)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.waitKey()
cv2.destroyAllWindows()
### threshold2
import sys
import numpy as np
import cv2
src = cv2.imread('cells.png', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
sys.exit()
def on_threshold(pos):
_, dst = cv2.threshold(src, pos, 255, cv2.THRESH_BINARY)
cv2.imshow('dst', dst)
cv2.imshow('src', src)
cv2.namedWindow('dst') #창을 미리 하나 만들어야 트랙바가 만들어진다
cv2.createTrackbar('Threshold', 'dst', 0, 255, on_threshold)
cv2.setTrackbarPos('Threshold', 'dst', 128)
cv2.waitKey()
cv2.destroyAllWindows()
### ostu
import sys
import numpy as np
import cv2
src = cv2.imread('rice.png', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
sys.exit()
#128대신 아무 숫자 넣어도 이 값으로 계산 안됨, 자동으로 결정된다
#강의에서는 대표 숫자 0을 입력함
#th는 실수형으로 리턴됨
#cv2.THRESH_BINARY | 없어도 똑같이 진행된다
th,dst=cv2.threshold(src, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
print("otsu's threshold:", th) # 131
cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()
### local_threshold
import sys
import numpy as np
import cv2
# 입력 영상 불러오기
src = cv2.imread('rice.png', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
sys.exit()
# 전역 이진화 by Otsu's method
_, dst1 = cv2.threshold(src, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
# 지역 이진화 by Otsu's method
dst2 = np.zeros(src.shape, np.uint8)
bw = src.shape[1] // 4 #block width , 128
bh = src.shape[0] // 4 #block height, 128
for y in range(4): #세로 4등분
for x in range(4): #가로 4등분
#copy가 아니기 때문에 dst_를 변경하면 dst2도 변경됨을 인지해야한다
# print(y*bh,'부터',(y+1)*bh, x*bw,'부터',(x+1)*bw)
#y=0일때 y는 0:128 고정이고, x방향으로 0:128, 128:256, 256:384, 384:512
#y=1일때 y는 128:256 고정이고, x방향으로 0:128, 128:256, 256:384, 384:512
src_ = src[y*bh:(y+1)*bh, x*bw:(x+1)*bw]
dst_ = dst2[y*bh:(y+1)*bh, x*bw:(x+1)*bw]
#dst_를 인자로써 입력은 dst_를 입력이자 출력으로 사용한다는 것
#만일 인자로 주지 않고 _,dst_= cv2.thresh~~ 로 작성하면
#새로운 정보로 채워진 dst_는 기존에 받았던 부분영상 정보가 없어진다
#src_,dst_ 크기가 같아야한다. 다르면 dst_가 또 정보를 잃게 되어서(dst2와 같은 정보를 공유하는 것을 못하게됨) 아예 새로운 형태를 만든다
cv2.threshold(src_, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU, dst_)
# 결과 출력
cv2.imshow('src', src)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.waitKey()
cv2.destroyAllWindows()
### adaptive_threshold
import sys
import numpy as np
import cv2
src = cv2.imread('sudoku.jpg', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
sys.exit()
def on_trackbar(pos):
bsize = pos
if bsize % 2 == 0: #짝수이면 하나를 빼서 홀수로 만듦(kernel은 반드시 홀수)
bsize = bsize - 1
if bsize < 3:
bsize = 3
dst = cv2.adaptiveThreshold(src, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, bsize, 5)
cv2.imshow('dst', dst)
cv2.imshow('src', src)
cv2.namedWindow('dst')
cv2.createTrackbar('Block Size', 'dst', 0, 200, on_trackbar)
cv2.setTrackbarPos('Block Size', 'dst', 11)
cv2.waitKey()
cv2.destroyAllWindows()
### 모폴로지
import sys
import numpy as np
import cv2
src = cv2.imread('circuit.bmp', cv2.IMREAD_GRAYSCALE) #0또는 255인 기판 이미지
if src is None:
print('Image load failed!')
sys.exit()
# 3행 5열짜리의 행렬의 structure element
se = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 3))
dst1 = cv2.erode(src, se)
# 3행 3열의 의미는 상하좌우 방향으로 1픽셀을 팽창한다는 의미
dst2 = cv2.dilate(src, None)
cv2.imshow('src', src)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.waitKey()
cv2.destroyAllWindows()
### 지역이진화+모폴로지
import sys
import numpy as np
import cv2
src = cv2.imread('rice.png', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
sys.exit()
# src 영상에 지역 이진화 수행 (local_th.py 참고)
dst1 = np.zeros(src.shape, np.uint8)
bw = src.shape[1] // 4
bh = src.shape[0] // 4
for y in range(4):
for x in range(4):
src_ = src[y*bh:(y+1)*bh, x*bw:(x+1)*bw]
dst_ = dst1[y*bh:(y+1)*bh, x*bw:(x+1)*bw]
cv2.threshold(src_, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU, dst_)
# connectedComponents: 흰색 덩어리가 몇개가 있는지 알려준다
# 모폴로지 하기전(잡음 제거전)
cnt1, _ = cv2.connectedComponents(dst1)
print('cnt1:', cnt1)
#침식과 팽창을 통해서 노이즈 제거 후 갯수 파악
# dst2 = cv2.morphologyEx(dst1, cv2.MORPH_OPEN, None)
dst2 = cv2.erode(dst1, None) #위에서 지역 이진화 진행한 dst1
dst2 = cv2.dilate(dst2, None)
cnt2, _ = cv2.connectedComponents(dst2)
# 모폴로지 시행 후(잡음 제거 후)
print('cnt2:', cnt2)
cv2.imshow('src', src)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.waitKey()
cv2.destroyAllWindows()
### labeling
import sys
import numpy as np
import cv2
src = cv2.imread('keyboard.bmp', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
sys.exit()
#1.먼저 이진화 작업
_, src_bin = cv2.threshold(src, 0,255, cv2.THRESH_OTSU)
#2.이진화 된 영상에서 레이블링을 작업
cnt, labels, stats, centroids=cv2.connectedComponentsWithStats(src_bin)
#stats나 centroids 정보를 통해서 각 객체가 어느위치에 어떻게 놓여 있는지 알수있다
#stats로 각각 객체의 바운딩 박스를 알수 있다 -> 각 객체를 구분 영상으로 짤라 낼수도있다
#3.각각의 객체 정보에 접근하기위해서 for문
dst = cv2.cvtColor(src, cv2.COLOR_GRAY2BGR)
for i in range(1,cnt): #1부터 시작한 이유: 배경 0 은 제외한다는 의미
x,y,w,h,a=stats[i]
'''
dst 영상의 빨간색 점들은 원본의 있는 노이즈
제거하기 위해서는 opening(침식&팽창)도 있지만
아래 처럼 간단하게 코드 작성한다
'''
#검출한 면적 수가 20보다 작으면 무시
if a <20:
continue
#빨간 바운딩 박스
cv2.rectangle(dst, (x,y,w,h),(0,0,255),2)
cv2.imshow('src', src)
cv2.imshow('src_bin', src_bin)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()
### 외곽선검출
import sys
import random
import numpy as np
import cv2
src = cv2.imread('contours.bmp', cv2.IMREAD_GRAYSCALE) #이진영상 load
if src is None:
print('Image load failed!')
sys.exit()
#1.외곽선 검출(좌표구하기)
#RETR_CCOMP: 2level(계층:2)
#CHAIN_APPROX_NONE: 모든 좌표 정보 저장
contours, hier = cv2.findContours(src, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
dst = cv2.cvtColor(src, cv2.COLOR_GRAY2BGR)
idx = 0 #첫번째 사용할 외곽선 인덱스 0번
while idx >= 0:
c = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
#검출한 외곽선좌표를 이용한 외곽선 그리기
#hier인자를 주면 홀 외곽선도 취급이 가능하다
#hier인자가 없다면 바깥의 외곽선만 취급한다.
#contours: 외곽선 좌표정보
cv2.drawContours(dst, contours, idx, c, 2, cv2.LINE_8, hier)
# hier의 shape가 (1,N,4)형태를 가진다
#[0, idx, 0], 무조건 첫번째는 0을 주면되고 N자리에 index번호를 준다.
#N은 외곽선의 갯수이다.
#맨 마지막 자리에 0부터3사이에 값을 줄수 있는데 0을 주면 계층에서 next로 넘어간다
#index번호에 따라서 next로 이동을 한다는 의미
idx = hier[0, idx, 0]
cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()
### 외곽선검출2
import sys
import random
import numpy as np
import cv2
src = cv2.imread('milkdrop.bmp', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
sys.exit()
_, src_bin = cv2.threshold(src, 0, 255, cv2.THRESH_OTSU)
#RETR_LIST: 모든 외곽선을 검출(리스트로 표현)
#hier 인자는 받지 않았음
contours, _ = cv2.findContours(src_bin, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
h, w = src.shape[:2]
dst = np.zeros((h, w, 3), np.uint8)
#contours는 리스트이기 때문에 contours의 길이는 객체의 갯수와 같다
for i in range(len(contours)):
c = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
cv2.drawContours(dst, contours, i, c, 1, cv2.LINE_AA)
cv2.imshow('src', src)
cv2.imshow('src_bin', src_bin)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()
import math
import cv2
def setLabel(img, pts, label):
(x, y, w, h) = cv2.boundingRect(pts) #외곽선을 감싸는 가장 작은 크기 사각형 정보출력
pt1 = (x, y)
pt2 = (x + w, y + h) #(가로길이,세로길이)
cv2.rectangle(img, pt1, pt2, (0, 0, 255), 1)
cv2.putText(img, label, pt1, cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 255))
def main():
img = cv2.imread('polygon.bmp', cv2.IMREAD_COLOR)
if img is None:
print('Image load failed!')
return
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#이진 영상만들기
#이때 THRESH_BINARY_INV사용해서 반전을 시킨다
#본 이미지의 도형은 어두운 컬러이고 오히려 바탕이 회색에 가까운 밝은 픽셀이기 때문에 반전 시켜야한다
_, img_bin = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
#findContours: 각각의 객체를 찾는다
#RETR_EXTERNAL: 바깥쪽 외곽선만 검출
contours, _ = cv2.findContours(img_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
#contours는 ndarray를 원소로 갖고 있는 리스트이다
#for문을 돌리면 pts가 객체 하나하나의 외곽선 객체를 받아 올수 있게된다
for pts in contours:
#노이즈를 제거하기 위한 코드
#하나하나의 객체의 면적이 400보다 작으면 무시
#400: 가로세로 20씩
if cv2.contourArea(pts) < 400: # 너무 작으면 무시
continue
#근사화를 진행서 단순화 시킨다
#근사화된 좌표로 리턴된다
#만일 좌표10개로 표현된 도형이 마진을 통해 근사화를 거치면 적은 좌표로 표현이 가능
approx = cv2.approxPolyDP(pts, cv2.arcLength(pts, True)*0.02, True)
vtc = len(approx)
#좌표갯수가 3도 아니고 4도 아니면 원 모양인지를 계산하는 코드
if vtc == 3:
setLabel(img, pts, 'TRI')
elif vtc == 4:
setLabel(img, pts, 'RECT')
else:
length = cv2.arcLength(pts, True)
area = cv2.contourArea(pts)
ratio = 4. * math.pi * area / (length * length)
if ratio > 0.85:
setLabel(img, pts, 'CIR')
cv2.imshow('img', img)
cv2.waitKey()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
"""
Tesseract-ocr 설치하기
1. tesseract-ocr-w64-setup-v5.0.0-alpha.20200328 파일 다운로드
(https://digi.bib.uni-mannheim.de/tesseract/tesseract-ocr-w64-setup-v5.0.0-alpha.20200328.exe)
2. 설치 시 "Additional script data" 항목에서 "Hangul Script", "Hangul vertical script" 항목 체크,
"Additional language data" 항목에서 "Korean" 항목 체크.
4. 설치 후 시스템 환경변수 PATH에 Tesseract 설치 폴더 추가
(e.g.) c:\Program Files\Tesseract-OCR
4. 설치 후 시스템 환경변수에 TESSDATA_PREFIX를 추가하고, 변수 값을 <Tesseract-DIR>\tessdata 로 설정
5. <Tesseract-DIR>\tessdata\script\ 폴더에 있는 Hangul.traineddata, Hangul_vert.traineddata 파일을
<Tesseract-DIR>\tessdata\ 폴더로 복사
6. 명령 프롬프트 창에서 pip install pytesseract 명령 입력
"""
import sys
import random
import numpy as np
import cv2
import pytesseract
def reorderPts(pts):
idx = np.lexsort((pts[:, 1], pts[:, 0])) # 칼럼0 -> 칼럼1 순으로 정렬한 인덱스를 반환
pts = pts[idx] # x좌표로 정렬
if pts[0, 1] > pts[1, 1]: #x좌표로 구분된 두 그룹중 왼쪽그룹에서 y좌표가 더 작은 좌표를 0번인덱스준다
pts[[0, 1]] = pts[[1, 0]] #두개의 점을 스와핑하는 코드
if pts[2, 1] < pts[3, 1]: #x좌표로 구분된 두 그룹중 오른쪽그룹에서 y좌표가 큰게 인덱스2, 나머지 우측상단이 3번
pts[[2, 3]] = pts[[3, 2]]
return pts #좌측상단부터 반시계방향으로 돌아가는 pts
# 영상 불러오기
filename = 'namecard1.jpg'
if len(sys.argv) > 1:
filename = sys.argv[1]
src = cv2.imread(filename)
if src is None:
print('Image load failed!')
sys.exit()
# 출력 영상 설정
dw, dh = 720, 400 #명함을 편 상태의 영상크기를 미리 설정
#입력영상의 네개의 모서리를 넣을 자리를 미리 만듦
srcQuad = np.array([[0, 0], [0, 0], [0, 0], [0, 0]], np.float32)
#dw, dh를 이용해서 좌측상단부터 반시계 방향으로 돈다
dstQuad = np.array([[0, 0], [0, dh], [dw, dh], [dw, 0]], np.float32)
dst = np.zeros((dh, dw), np.uint8)
# 입력 영상 전처리_이진화
src_gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
_, src_bin = cv2.threshold(src_gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
# 외곽선 검출 및 명함 검출
contours, _ = cv2.findContours(src_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cpy = src.copy()
for pts in contours:
# 너무 작은 객체는 무시
if cv2.contourArea(pts) < 1000:
continue
# 외곽선 근사화
# approx: 점 네개로 근사화가 된다
approx = cv2.approxPolyDP(pts, cv2.arcLength(pts, True)*0.02, True)
# 컨벡스가 아니고, 사각형이 아니면 무시
if not cv2.isContourConvex(approx) or len(approx) != 4:
continue
#polylines통해 외곽선을 그린다
cv2.polylines(cpy, [approx], True, (0, 255, 0), 2, cv2.LINE_AA)
#reorderPts: 각 점의 순서를 수동으로 정해준다
#approx 점들을 분석해서 좌측상단부터 반시계방향으로 reorder => srcQuad로 넘긴다
srcQuad = reorderPts(approx.reshape(4, 2).astype(np.float32))
pers = cv2.getPerspectiveTransform(srcQuad, dstQuad)
#똑바로 펴는 작업
dst = cv2.warpPerspective(src, pers, (dw, dh))
dst_gray = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
print(pytesseract.image_to_string(dst_gray, lang='Hangul+eng'))
cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()
728x90
'실습 note' 카테고리의 다른 글
OpenCV_8(특징점 검출&매칭) (0) | 2021.02.26 |
---|---|
OpenCV_7(영상분할&객체검출) (0) | 2021.02.25 |
OpenCV_5(영상의 특징추출) (0) | 2021.02.23 |
OpenCV_4(기하학적 변환) (0) | 2021.02.22 |
버스 승차인원 예측 실습(데이콘 경진대회 1등 솔루션) (0) | 2021.02.20 |