파이썬 이미지 찾기 - paisseon imiji chajgi


python공부/python 코드

[파이썬 코드]이미지로 좌표 찾기

2021. 10. 27. 03:58

이미지로 찾아서 클릭

왼쪽 상단에서 오른쪽으로 픽셀을 검색하여 좌표를 찾음.
즉 똑같은 그림이 여러개 있다면, 가장 좌측 상단의 좌표만 리턴함.
똑같은 이미지가 없다면 FileNotFoundError


import pyautogui

def getCoordinateByImg(imgAddress):
    imgLocatedCoordinate = pyautogui.locateOnScreen(imgAddress)  # 이미지가 있는 위치를 가져옵니다.

    if (imgLocatedCoordinate):
        return pyautogui.center(imgLocatedCoordinate)  # 찾은 이미지의 중앙 좌표를 리턴
    else:
        print("image never found")
        raise FileNotFoundError

에러

  • pyscreeze.PyScreezeException: 터미널에 "pip install Pillow --upgrade" 을 쳐서 업데이트.


파이썬 이미지 찾기 - paisseon imiji chajgi

이미지 분류를 위한 딥러닝 모델을 만들던 중 학습 데이터가 필요해서 이미지를 크롤링 해왔으나 문제점이 있었다. 

모델을 만들 때 잘 정제된 학습 데이터를 쓰는 것과 그렇지 않은 것으로 학습 시킨 모델에 차이가 있기 때문에 중요하다. 

예를 들어서 아래 이미지는 Pixabay에서 가지고 온 화장품 사진인데, 화장품 주위에 필요없는 배경이 있어 이것이 모델을 학습시킬 때 어느정도 영향을 미치게 된다. 

파이썬 이미지 찾기 - paisseon imiji chajgi

따라서 목표는 OpenCV와 Python을 이용해서 원하는 부분만 잘라내는 것이다.

import cv2, sys

from matplotlib import pyplot as plt

import numpy as np

우선 이미지 처리를 위해 cv2와 파일을 읽어오고 저장하기 위해 sys를 import해준다.

이미지 확인을 위해 matplotlib의 pyplot을 import 했으나 필요 없다면 하지 않아도 무방하다.

리스트 배열을 넘파이로 처리하기 위해 numpy를 import 해주었다. 

image = cv2.imread('cosmetic.jpg')

image_gray = cv2.imread('cosmetic.jpg', cv2.IMREAD_GRAYSCALE)

cv2의 imread()를 이용해서 해당 경로의 이미지를 읽어 온다. 같은 폴더에 있다면 위와 같이 이미지 이름과 확장자만 적어도 된다. image는 원본 이미지를 읽어오고 image_gray는 cv2.IMREAD_GRAYSCALE을 통해 흑백 이미지로 읽어 온다. 

이미지가 너무 큰 경우 이미지 크기를 줄여야 한다. 

다음은 주피터(jupyter notebook)에서 이미지를 보이게 하는 방법이다. 

b,g,r = cv2.split(image)

image2 = cv2.merge([r,g,b])

plt.imshow(image2)

plt.xticks([])

plt.yticks([])

plt.show()

읽어온 이미지는 r,g,b 세층으로 이루어져 있는데 이를 분리하면 순서대로 b,g,r 층이 되므로 이를 변수에 담아 다시 순서대로 r,g,b 순으로 image2에 담는다. 

그 후 파이플롯으로 해당 이미지를 띄우면 된다. 

파이썬 이미지 찾기 - paisseon imiji chajgi
결과 화면

주피터 jupyter에서 윈도우 창에 띄울 수 있기 때문에 윈도우 창에 띄우는 방법을 사용했다. 

cv2.imshow('image', image)

cv2.imshow('image_gray', image_gray)

cv2.waitKey(0)

cv2.destroyAllWindows()

파이썬 이미지 찾기 - paisseon imiji chajgi
결과 창

이제 부터 이미지에서 화장품만 가져오기 위해 가우시안 블러를 사용한다. 

블러는 이미지를 부드럽게 하기 때문에 배경과 원하지 않는 부분을 부드럽게 하여 해당 경계를 찾지 못하게 하기 위함이다. 블러 처리를 심하게 하면 원래 찾고자 하는 대상을 찾지 못하게 되고, 블러가 약하면 배경의 외곽도 포함되므로 ksize를 적당히 조절 해야 한다. 

blur = cv2.GaussianBlur(image_gray, ksize=(3,3), sigmaX=0)

ret, thresh2 = cv2.threshold(blur, 127255, cv2.THRESH_BINARY)

파이썬 이미지 찾기 - paisseon imiji chajgi
ksize = (3, 3)

blur = cv2.GaussianBlur(image_gray, ksize=(5,5), sigmaX=0)

ret, thresh2 = cv2.threshold(blur, 127255, cv2.THRESH_BINARY)

파이썬 이미지 찾기 - paisseon imiji chajgi
ksize = ( 5 , 5 )

어떤 이미지에 대해서 ksize=(3,3)으로 해 주는 것이 외곽을 잘 찾는다. 외곽의 수를 적게 찾아내도록 알고리즘을 짜주면 되겠지만 지금은 ksize=(5,5)로 해줄 때 원하는 이미지의 외곽을 잘 찾는다 판단하고 넘어가기로 한다. 위와 같이 외곽을 검출할려면 아래와 같은 코드가 필요하다. 

edged = cv2.Canny(blur, 10250)

cv2.imshow('Edged', edged)

cv2.waitKey(0)

Canny()를 이용하여 모서리(외곽)을 찾아 낸뒤 윈도우에 띄워 주면 된다.

파이썬 이미지 찾기 - paisseon imiji chajgi
Canny( ) 결과 화면

다음은 엣지 이미지로 closed를 찾는다.

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7,7))

closed = cv2.morphologyEx(edged, cv2.MORPH_CLOSE, kernel)

cv2.imshow('closed', closed)

cv2.waitKey(0)

파이썬 이미지 찾기 - paisseon imiji chajgi

하얀 선이 굵어 지면서 edge 이미지에서 보이는 각 경계들이 이어지면서 중간에 끊어지지 않는 선이 된 것을 확인할 수 있다. 

다음으로 컨투어를 찾는다. close이미지와 findContours()를 이용하여 컨투어 경계를 찾는다. 

contours, _ = cv2.findContours(closed.copy(),cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

total = 0

파이썬 이미지 찾기 - paisseon imiji chajgi

# 외곽선 그리는 용도. 이미지에 그리기 때문에 이 코드 적용하면 원래 이미지에

# 초록색 선 생김

contours_image = cv2.drawContours(image, contours, -1, (0,255,0), 3)

cv2.imshow('contours_image', contours_image)

cv2.waitKey(0)

cv2.destroyAllWindows()

위 코드는 적용하지 않고 넘어가셔도 됩니다. drawContours()를 이용해서 이미지의 외곽을 그립니다. 

contours_xy = np.array(contours)

contours_xy.shape

외곽을 저장하고 있는 contours는 외곽의 점들이 모여 선을 나타내므로 각 점의 좌표를 가지고 있습니다.

리스트를 넘파이 array로 바꾸어서 형태를 알아봅니다. 

contours[] => 물체가 몇 개인지 나타냅니다. 하나의 닫힌 선이 물체 하나를 인식합니다. 위에서는 다른 것을 인식하지 않고 향수병만 인식했으므로 물체는 한 개 입니다. 

contours[][] => 이 때부터 각 좌표를 나타냅니다

contours[][][x][y] -> 세번째와 네번째 부터는 각각 x축과 y축을 나타냅니다. 

OpenCV에서 이미지의 좌표는 다음과 같이 나타납니다. 

파이썬 이미지 찾기 - paisseon imiji chajgi

x축은 오른쪽으로 갈 수록 증가하고 y축은 아래로 내려갈 수록 증가합니다. 원하는 이미지가 있다고 한다면

파이썬 이미지 찾기 - paisseon imiji chajgi

아래와 같이 잘라내야 합니다. 

파이썬 이미지 찾기 - paisseon imiji chajgi
파이썬 이미지 찾기 - paisseon imiji chajgi

컨투어, 즉 앞에서 찾아낸 외곽 정보로 물체가 가지는 x 좌표값, y좌표값의 각 최대값과 최소값을 알아 낼 수 있습니다. 이제 빨간 선으로 만들어지는 사각형의 모서리를 보면

파이썬 이미지 찾기 - paisseon imiji chajgi

각 모서리에 대한 좌표를 얻을 수 있습니다! 이를 적용하기 위해 외곽 좌표값으로 부터 각각 x와 y를 찾도록 코드를 짜줍니다. 물체가 여러개일 수도 있다는 것을 반영하여 작성했습니다. 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

# x의 min과 max 찾기

x_min, x_max = 0,0

value = list()

for i in range(len(contours_xy)):

for j in range(len(contours_xy[i])):

value.append(contours_xy[i][j][0][0]) #네번째 괄호가 0일때 x의 값

x_min = min(value)

x_max = max(value)

print(x_min)

print(x_max)

# y의 min과 max 찾기

y_min, y_max = 0,0

value = list()

for i in range(len(contours_xy)):

for j in range(len(contours_xy[i])):

value.append(contours_xy[i][j][0][1]) #네번째 괄호가 0일때 x의 값

y_min = min(value)

y_max = max(value)

print(y_min)

print(y_max)

이미지를 자르기 위해 높이와 넓이를 구해 줍니다. 각 축의 최대에서 최소값을 빼주면 얻을 수 있습니다. 

# image trim 하기

= x_min

= y_min

= x_max-x_min

= y_max-y_min

위에서 image[]는 원본 이미지를 담았던 변수 입니다. 이미지를 자른 이미지를 저장해 줍니다. 

다시 org_image에 불러와서 잘 잘렸는지 확인해 봤습니다.

cv2.waitKey(0)

cv2.destroyAllWindows()

파이썬 이미지 찾기 - paisseon imiji chajgi
원하는 부분만 잘라낸 이미지

원하는 부분이였던 화장품만 잘 잘린것을 확인 할 수 있었습니다.

참고 사이트 

A guide to finding books in images using Python and OpenCV.

This is a guest post by Adrian Rosebrock from PyImageSearch.com, a blog all about computer vision, image processing, and building image search engines.

pythontips.com