OpenCV/머신비전

top.ipynb 코드블럭 (이진화, 꼭짓점 좌표, 원(ing) 검출)

Raccoon2125 2020. 12. 18. 09:42
backup
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]
1920
1080
Out[1]:
'c:\\Users\\w\\Desktop\\contents\\machineVision'
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()
[[1111, 986], [243, 984], [245, 150], [1113, 151]]
(1080, 1440, 3)
(1080, 1440, 3)
uint8
uint8