OpenCV/머신비전
top.ipynb 코드블럭 (이진화, 꼭짓점 좌표, 원(ing) 검출)
Raccoon2125
2020. 12. 18. 09:42
In [1]:
import cv2
import numpy as np
import pandas as pd
from win32api import GetSystemMetrics
import sys
print(GetSystemMetrics(0))
print(GetSystemMetrics(1))
sys.path[0]
Out[1]:
In [2]:
def imread(filename, flags=cv2.IMREAD_COLOR, dtype=np.uint8):
try:
n = np.fromfile(filename, dtype)
img = cv2.imdecode(n, flags)
return img
except Exception as e:
print(e)
return None
In [3]:
def fitSizeImage(_image):
height = _image.shape[0]
width = _image.shape[1]
monitor_height = GetSystemMetrics(1)
monitor_width = GetSystemMetrics(0)
if (height > monitor_height or width > monitor_width):
tmp_x1 = monitor_height / height
tmp_x2 = monitor_width / width
tmp_min = min(tmp_x1, tmp_x2)
image = _image.copy()
image = cv2.resize(image, dsize = (0, 0), fx = tmp_min, fy = tmp_min, interpolation = cv2.INTER_AREA) # (1080, 1437, 3)
return image
In [4]:
def findOuterRect(imageGray, thresholdValue = 75, _type = cv2.THRESH_TOZERO):
_, imageBinary = cv2.threshold(imageGray, thresholdValue, 255, type = _type)
imageCanny = cv2.Laplacian(imageBinary, cv2.CV_8U)
imageCanny = cv2.Canny(imageCanny, 127, 255)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
imageMorph = cv2.morphologyEx(imageCanny, cv2.MORPH_CLOSE, kernel, iterations = 3)
contours, _ = cv2.findContours(imageMorph, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
maxContours = max(contours, key = cv2.contourArea) # 최대 테두리
rect = cv2.minAreaRect(maxContours) # minAreaRect
box = cv2.boxPoints(rect)
box = np.int0(box)
forDfList = []
for i in range(box.shape[0]):
forDfList.append(list(box[i])) # 데이터프레임 생성용 리스트
print(forDfList)
# 좌표 DataFrame에 담기 / 0(우하), 1(좌하), 2(좌상), 3(우상), 4(우하)
rectDf = pd.DataFrame(forDfList, columns = ['x', 'y'])
tmp = list(rectDf.loc[0])
rectDf = rectDf.T
rectDf['4'] = tmp
rectDf = rectDf.T
# 좌표 간 연산 수행 및 중점 잡아서 텍스트 넣기
distanceList = []
locationList = []
for i in range(4):
front_x = rectDf.iloc[i, 0]; behind_x = rectDf.iloc[i + 1, 0]
front_y = rectDf.iloc[i, 1]; behind_y = rectDf.iloc[i + 1, 1]
minX = min(front_x, behind_x)
minY = min(front_y, behind_y)
x = np.abs(front_x - behind_x)
y = np.abs(front_y - behind_y)
locationX = int(minX + x/2)
locationY = int(minY + y/2)
locationList.append([locationX, locationY])
distance = np.sqrt(np.power(x, 2) + np.power(y, 2))
distance = np.round(distance/100, 2)
distanceList.append(distance) # distanceList = [8.33, 8.34, 8.33, 8.34]
# 혹시 모를 재사용을 위해 원본으로 복원
rectDf.drop(['4'], axis = 0, inplace = True)
return imageGray, imageMorph, imageBinary, imageCanny, distanceList, rectDf, box, locationList
# 메인 함수 시작
for picNum in range(22, 23): # 22번이 가장 에러가 많음(기준 이미지 설정)
#for picNum in range(1, 31):
#for picNum in range(1, 6):
#for picNum in range(6, 11):
#for picNum in range(11, 16):
#for picNum in range(16, 21):
#for picNum in range(21, 26):
#for picNum in range(26, 31):
#teset_list = [18, 24] # 에러만 모아놓은 리스트
#for picNum in small_list:
# 이미지 로드 및 프로세싱
image = imread('C:/Users/w/Desktop/contents/machineVision/PCB2/04_top/' + str(picNum) + '.bmp')
image = fitSizeImage(image) # 29.bmp 기준 shape = (1080, 1440, 3)
imageCopy = image.copy()
imageGray = cv2.cvtColor(imageCopy, cv2.COLOR_BGR2GRAY)
cv2.putText(imageCopy, str(picNum), (50, 50), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 0, 255), 2)
######################################### 최외곽 네모 #######################################
# 일단 기준이 되는 이미지를 그리고 연산을 수행합니다. 가장 정확도가 높았던 값을 먼저 사용합니다.
imageGray, imageMorph, imageBinary, imageCanny, distanceList, rectDf, box, locationList = findOuterRect(imageGray, thresholdValue = 75, _type = cv2.THRESH_TOZERO)
# count = 0
# while all(np.array(distanceList) > 8.0) or all(np.array(distanceList) < 8.4):
# # 수행된 연산의 값을 토대로 기준점 미달 시 새롭게 이미지 연산을 수행합니다.
# if any(np.array(distanceList) < 8.0):
# imageGray, imageMorph, imageBinary, imageCanny, distanceList, rectDf, box, locationList = findOuterRect(imageGray, thresholdValue = 75 + count, _type = cv2.ADAPTIVE_THRESH_GAUSSIAN_C)
# count += 1
# print(count)
# elif any(np.array(distanceList) > 8.4):
# imageGray, imageMorph, imageBinary, imageCanny, distanceList, rectDf, box, locationList = findOuterRect(imageGray, thresholdValue = 75 + count, _type = cv2.ADAPTIVE_THRESH_GAUSSIAN_C)
# count -= 1
# print(count)
cv2.drawContours(imageCopy, [box], 0, (0, 255, 0), 1) # 테두리 그리기
# 좌표 찍기, 텍스트 삽입 /// 참고: box.shape(4, 2) / box.dtype = np.uint64
for i in range(box.shape[0]):
cv2.circle(imageCopy, tuple(box[i]), 5, (0, 255, 255), cv2.FILLED, cv2.LINE_4)
cv2.putText(imageCopy, str(box[i][0]) + " : " + str(box[i][1]), tuple(box[i]), cv2.FONT_HERSHEY_COMPLEX, 0.45, (0, 0, 255), 1)
for i in range(4): # distanceList[인덱스] 형태로 바꿔야함
cv2.putText(imageCopy, str(distanceList[i]), (tuple(locationList[i])), cv2.FONT_HERSHEY_COMPLEX, 0.6, (255, 0, 0), 2)
######################## 원 검출 ######################
_, imageBinary2 = cv2.threshold(imageGray, 105, 255, type = cv2.THRESH_BINARY_INV) # 이진화
# 가장 외곽에 있는 원
# imageCopy.shape = (1080, 1440, 3)
bigCircles = cv2.HoughCircles(imageBinary2, cv2.HOUGH_GRADIENT, 1, 900, param1 = 150, param2 = 5, minRadius = 320, maxRadius = 325)
circleZeros = np.zeros(imageCopy.shape, dtype = np.uint8)
print(circleZeros.shape)
for i in bigCircles[0]:
cv2.circle(imageCopy, (i[0], i[1]), int(i[2]), (0, 255, 255), 2)
cv2.circle(circleZeros, (i[0], i[1]), int(i[2]), (255, 255, 255), -1)
circleX = i[0]
circleY = i[1]
cv2.circle(imageCopy, (circleX, circleY), 2, (255, 255, 0), 2)
testImage = cv2.merge((imageBinary2, imageBinary2, imageBinary2))
print(testImage.shape)
print(testImage.dtype)
print(circleZeros.dtype)
testImage2 = cv2.bitwise_and(circleZeros, testImage)
cv2.imshow('testImage', testImage)
cv2.imshow('testImage2', testImage2)
#circleContours, _ = cv2.findContours(circleZeros, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
#maxCircleContour = max(circleContours, key = cv2.contourArea)
#cv2.drawContours(circleZeros, [maxCircleContour], 0, (0, 255, 255), 2)
cv2.imshow('circleZeros', circleZeros)
# 테두리 검출
# _, imageBinary = cv2.threshold(imageGray, 90, 255, type = cv2.THRESH_BINARY_INV) # 이진화
# contours, _ = cv2.findContours(imageBinary, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE) # 테두리 찾기
# for contour in contours:
# cv2.drawContours(imageCopy, [contour], 0, (255, 255, 0), 5)
# _area = cv2.contourArea(contour)
# forDfList.append([_area, contour])
# mixedDf = pd.DataFrame(forDfList, columns = ['contour', 'area'])
# display(mixedDf.head(3))
# mixedDf.sort_values('contour', ascending = False, inplace = True)
# cv2.drawContours(imageCopy, [mixedDf.iloc[1, 1]], 0, (0, 0, 255), 5)
cv2.imshow('imageGray', imageGray)
cv2.imshow('imageMorph', imageMorph)
cv2.imshow('imageBinary', imageBinary)
cv2.imshow('imageBinary2', imageBinary2)
cv2.imshow('imageCanny', imageCanny)
cv2.imshow('imageCopy', imageCopy)
cv2.waitKey(0)
cv2.destroyAllWindows()