ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Project_AF] 자동초점 현미경 개발기 (4) - 초점 확인 알고리즘
    Ort Lab 2020. 3. 5. 01:32

    전 글이 생각보다 심각하게 길어진 관계로... 이어서 바로 가겠습니다!

     

    네 뭐 방법은 전 글에서 대충 설명했고.. 이걸 한번 프로그램적으로 적용해보겠습니다. 

     

    전 파이썬을 통해서 프로그래밍할 예정이기에... 파이참을 사용합니다.

     

    일단.. Sobel Algorithm 이라는것이 있습니다. 이 알고리즘은 이미지를 미분합니다.

    x축방향으로 미분하다고 하면 현 픽셀(x,y)의 값을 │(x,y의 밝기) - (x+1,y의 밝기) 로 치환합니다.

     

    저게 뭔소리냐면..  밝기의 차이만큼을 현 픽셀의 값으로 리턴시키는 겁니다. (참 쉽죠?)

    자 그럼.. 차차 진행해보죠

     

    일단! (image.jpg)를 불러와서 흑백(GrayScale)로 바꿔줍니다.

    import cv2
    
    img = cv2.imread("Image.jpg", cv2.IMREAD_COLOR)
    
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    cv2.imshow("original", img)
    cv2.imshow("gray", img_gray)
    
    
    img_data = img_gray
    cv2.imwrite('result.jpg',img_data)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    네. 뭐 대충 이럽니다. (어쩌라고) 

    대충 해석해보자면..

    3번째 줄에서 image.jpg 를 불러와서 img로 지정합니다.

    5번째 줄에서 cv2.COLOR_BRG2GRAY가 있는데 이게 그레이스케일. 흑백으로 변환하는 코듭니다.

     

    img

     

    요거가

     

     

    이렇게 됩니다! (네 뭐 흑백으로 바꿨으니 당연한거죠.)

     

    그럼여기다가 Sobel Algorithm을 적용해보죠.

    단. 여기서 감안해야될것은 소벨알고리즘(영어쓰기 귀찮기에...)은 위에서 설명했듯이.. 특정 방향으로서의 밝기값 변화량 입니다. 일단 x방향으로 소벨알고리즘을 써보죠.

    def Sobel(img):
        img_sobel_x = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
        img_sobel_x = cv2.convertScaleAbs(img_sobel_x)
        return img_sobel_x

    쪼그만 함수를 하나 추가해줍니다.

    소벨알고리즘은 아주 편리하게도 opencv에서 자체적으로 제공됩니다!

    네 2번줄에서 소벨알고리즘을 돌립니다. x축방향으로요.

    그리고 3번째 줄이 뭔가 싶으실텐데... 저건 절댓값을 씌우고 unsigned int로 변환해주는겁니다.

    이것의 출력결과를 보면..

     

     

    네, 이런식으로 나오게 됩니다. 그림에서 보면 하얀부분은 밝기의 변화가 있는곳입니다. 윗 그림이랑 대조해보세요.

    근데.. 이건 x방향으로만 계산한겁니다. 그럼 y축으로도 해봐야겠죠?

    def Sobel(img):
        img_sobel_y = cv2.Sobel(img_gray, cv2.CV_64F, 0, 1, ksize=3)
        img_sobel_y = cv2.convertScaleAbs(img_sobel_y)
        return img_sobel_y

    1,0 이 0,1로 바뀐거밖에 없습니다.

     

     

    요로코옴 보이네요.

    아까 img_sobel_x랑 차이점이 느껴지시나요? 잘 모르시겠으면 세포 핵을 잘 보세요. img_sobel_x는 가로쪽이 더 선명하고 img_sobel_y는 세로쪽이 더 선명한 모습을 보입니다.

     

    당연하게도.. 이걸 선명도를 뽑는용도로 쓰려면 두 이미지를 합쳐야겠죠?

    addWeidghted함수를 사용할겁니다.

    def Sobel(img):
        img_sobel_x = cv2.Sobel(img_gray, cv2.CV_64F, 1, 0, ksize=3)
        img_sobel_x = cv2.convertScaleAbs(img_sobel_x)
    
        img_sobel_y = cv2.Sobel(img_gray, cv2.CV_64F, 0, 1, ksize=3)
        img_sobel_y = cv2.convertScaleAbs(img_sobel_y)
    
        img_sobel = cv2.addWeighted(img_sobel_x, 1, img_sobel_y, 1, 0);
    
        return img_sobel

    네 이렇게 img_sobel_x와 img_sobel_y를 addWeighted로 합쳐주시면..

     

     

    네! 최종적으로 이런 이미지가 나오게 됩니다!

    이게 소벨알고리즘이 적용된 이미지.. 입니다.

    그리고 재미삼아서 반전을 적용해주면..

     

     

    네 이럽니다 ㅋㅋㅋㅋㅋ(그냥해봄)

     

    저건 무시하고.. 이제 저기서 이미지의 평균 밝기변화율을 구하면 됩니다.

    근데.. 우린 이미 이미지의 밝기변화율로 전환된 이미지가 있잖아요?

    네 소벨알고리즘이 적용된 이미지 입니다!

     

    그냥 별거 없고.. 소벨알고리즘 적용된 이미지의 각 픽셀값을 싸그리 다 더해주면 끝입니다. 

    그냥 다 더하세요. (설명해라)

     

    일단.. 이미지는 2차원 리스트로 이루어져 있습니다.

    전 글에 익숙한 그 그림! 재탕입니다 ㅋㅋ

     

     

    저 이미지에 끝에 각각 좌표를 적어놨습니다. 네. 저런식으로 이미지에 나타나는데.. 이게 컴퓨터 내부에는 이렇게 나타나 있습니다.

     

     

    (찐텐으로 이거 쓰기 힘들었습니다 ㅋㅋㅋㅋㅋㅋㅋ)

    네 저런식으로 저장되어있습니다. 그럼으로 img의 (x,y)좌표 픽셀값을 알아내기위해서는 img[y][x]로 해야합니다.

    (2차원 리스트의 문법을 참고하시길..)

     

    그럼으로 이거를 이용해서.. 모든픽셀의 픽셀값을 싸그리 다 더합니다.

    근데.. 이걸 하는 이유는 초점이 맞았는지를 알기 위해서잖아요? 그러니까 픽셀값을 제곱을 합니다.

    왜 제곱을 하느냐 라면.. 초점이 잘 맞을수록 선명도가 가파르게 증가하도록 하기 위해서 입니다.

     

    이를 아까 Sobel함수의 return을 불러와서.. 선명도를 구하는 함수를 짜도록 하죠.

    def get_Definition(img_sobel):
        sum_data = 0
    
        for y in range(0, len(img_sobel), 1):
            for x in range(0, len(img_sobel[y]), 1):
                sum_data += (int(img_sobel[y, x]) ** 2)
        sum_data = sum_data / (len(img_sobel) * len(img_sobel[y]))
    
        return int(sum_data)

    네. 요겁니다.

    2번줄에서 합한값을 정의해주고요, 4~6까지는 sum_data에 각 픽셀의 값의 제곱의 합들을 누적합니다.

    7번줄에서는 sum_data를 총 픽셀수로 나누어줍니다. 

    이렇게 되면 return된 sum_data는 입력한 img_sobel의 평균 밝기라고 할 수 있습니다.

    img_sobel이 밝기의 변화량을 나타내는 데이터였으니, 위에 Sobel(img)와 조합하면, img라는 입력 사진의 평균 밝기변화량이 됩니다. 

     

    프로그램을 실행시키면.. (13200)이 출력되네요. 

    결과적으로 이 수는 입력한 최초사진 image.jpg 의 선명도가 됩니다.

     

    물론 프로그램의 특성상, 사진에 따라 선명도라는 것은 주관적으로 변할 수 있습니다.

    그러나, 초점이 맞았는지를 확인한다는 목적때문에 기본조건 사진(초점이 맞을 현미경의 타겟 상)은 일정합니다.

    즉, 초점이 딱 맞아 선명하게 보일때 선명도가 최대이지, 초점이 맞지 않으면 무조건 선명도는 선명하게 보일때보다 낮을수밖에 없다는겁니다. 즉, 현미경의 제물대를 움직일때는 

     

     

    이런형태의 그래프가 나올수밖에 없다는 거죠. 

    그럼.. 초점이 맞을수록 프로그램에서 도출되는 선명도가 높다는것. 이것을 확인해봅시다.

    당연히 ( 초점이 맞는다 = 선명도가 높다 )겠죠?

     

    1
    2

     

    비교를 위해 선명도가 다른(파워포인트로 선명도를 인위적으로 조절했습니다.) 이미지를 프로그램에 넣고 돌려보죠.

    1번사진은 (4503)이 출력되었습니다.

    2번사진은 (24)가 출력되었습니다.

     

    네! 아주 잘되네요 기분이 좋습니다!

     

    이렇게 프로그램적으로 이미지의 선명도를 구해보았습니다!

     

    마지막으로 소스코드 전체는 다음과 같습니다.

    import cv2
    
    def Sobel(img):
        img_sobel_x = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
        img_sobel_x = cv2.convertScaleAbs(img_sobel_x)
    
        img_sobel_y = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
        img_sobel_y = cv2.convertScaleAbs(img_sobel_y)
    
        img_sobel = cv2.addWeighted(img_sobel_x, 1, img_sobel_y, 1, 0);
    
        return img_sobel
    
    def get_Definition(img_sobel):
        sum_data = 0
    
        for y in range(0, len(img_sobel), 1):
            for x in range(0, len(img_sobel[y]), 1):
                sum_data += (int(img_sobel[y, x]) ** 2)
        sum_data = sum_data / (len(img_sobel) * len(img_sobel[y]))
    
        return int(sum_data)
    
    img = cv2.imread("Image.jpg", cv2.IMREAD_COLOR)
    
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    img_data = Sobel(img_gray)
    Definition = get_Definition(img_data)
    print(Definition)
    
    cv2.imshow('Sobel',img_data)
    cv2.imwrite('result.jpg',img_data)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    저 프로그램을 돌리려면 같은 디렉토리상의 Image.jpg 라는 이름을 갖는 이미지파일이 있어야 합니다.

     

    벌써 1시 30분이네요. 그럼 이만....

    댓글

Designed by Tistory.