Blog

  • 이미지 crop

    이건 굉장히 쉽다. 원본 이미지 변수에서 행과 열의 순서대로 범위를 지정하면 된다. 어려운 점은 0부터 시작한다는 것이다. 내가 잘 모르는 것이라면.. 100픽셀로 하려면 하나 더 더해주어야 한다는 것이다. 다음의 식으로 쭉 훑는 방법을 적용해 보았다.

    src = cv2.cvtColor(cv2.imread("seq2337.tif"), cv2.COLOR_BGR2RGB)
    src_height = src.shape[0]
    src_weight = src.shape[1]
    for i in range(0, np.int(src_height/100)+1):
        for ii in range(0, np.int(src_weight/100)+1):
            crop = src[(i*100):(i*100+99+1), (ii*100):(ii*100+99+1)]
    

  • 이미지 복사

    OpenCV에서 이미지를 복제할 때 R 처럼 src2 = src 했더니 상호 연동이 되었다. .copy()를 이용해서 해야 독립적이다.

    src_color = cv2.cvtColor(cv2.imread("seq2337_1.tif"), cv2.COLOR_BGR2RGB)
    src_color2 = src_color.copy()
  • RGB vs. BGR

    최근의 일반적인 이미지 프로그램들은 색상을 저장할 때 RGB 순서대로 저장을 한다. 그런데 OpenCV에서 imread로 파일을 불러올 때에는 BGR 순서대로 불러오는 것 같다. 인터넷 검색을 해보면 초기에 카메라 업체들이 파일을 저장할 때 BGR를 이용했기 때문에 이런것 같다는 내용을 찾아볼 수 있다. 어제 염색 색상이 다르게 보이길래 모니터 색상이 문제인가 싶었는데, 그것치고는 너무 심하여 아마 이 순서에 따른 문제로 판단했다. cvtColor로 쉽게 변환할 수 있다.

    cv2.cvtColor(cv2.imread("seq2337_1.tif"), cv2.COLOR_BGR2RGB)
    

    진짜 웃긴건 drawContours로 박스를 그릴 때 색상은 RGB 순서대로 들어간다. 아래와 같이 입력하면 빨간색 테두리가 생긴다. 하하하…

    cv2.drawContours(src, [np.int64(cv2.boxPoints(rect))], 0, [255, 0, 0])
  • 슬라이드 개체 인식

    보다 자세하게는 현미경 소견에서 관찰되는 개체를 인식할 수 있는가에 대한 것이다. 일단 고전적인 방법으로 접근하여 보았다. 인터넷 동호회의 정보를 바탕으로 모멘트(moments)에 대한 것을 검색하기 시작했고, 컨투어(contour)가 내가 원하는 기능이라는 것을 확인했다. 유채색을 고려하는 알고리즘은 못 찾았다. 그래서, 고전적인 방법으로 해보기로 했다. 이 방법에 있어서

    가장 중요한 것은 분석 대상이 잘 구분되는 gray scale 이미지 변환이다.

    OpenCV를 이용하여 시도해 보았던 방법은 RGB를 HSV로 변경하여 low와 high 범위내의 색상을 추출하는 것인데, 영 시원찮았다. CellProfiler를 이용하여 추출한 흑백 이미지를 이용했다. 이 경우에도 1-channel이 아니었기 때문에 변환시켜 준다.

    src = cv2.imread("seq2337_1gray.tiff", cv2.IMREAD_GRAYSCALE)

    Python의 경우 함수에서 결과를 여러개 나오는 경우가 있다. 이럴 경우 순서에 맞게 출력하거나, 불필요하게 들어오는 것은 대충 처리하거나 하는 것 같다.

    분석 대상이 아닌 배경 이미지는 확실하게 지워줘야 한다. threshold의 경우 첫 번째꺼는 쓰지 않는 정보이다. 2번째는 low값, 3번째는 high 값, 4번째는 출력 방식이다.

    ret, gray_th = cv2.threshold(src, 100, 255, cv2.THRESH_BINARY)
    아니면
    gray_th = cv2.threshold(src, 100, 255, cv2.THRESH_BINARY)[1]
    

    Contours를 찾아주는 것은 아래와 같이 하면 된다. 2번째와 3번째는 contours를 설정하는 방법에 대한 것이다. 나는 findContours의 결과 중 첫 번째 Contours에 위치에 대한 정보만 있으면 된다. R과 Python의 중요한 차이점으로 처음이 1이 아닌 0이다.

    contours = cv2.findContours(
                 gray_th, cv2.RETR_TREE, cv2.CHAIN_APPROX_TC89_KCOS)[0]
    

    Contours가 여러개 나오기 때문에 반복문을 이용해서 [i]가 있다. 이미지는 항상 똑바르게 서있거나 누워 있지 않기 때문에, 기울어진 직사각형으로 contours를 찾는 minAreaRect를 이용했다.

    rect = cv2.minAreaRect(contours[i])
    

    minAreaRect에서는 결과값이 3개가 나온다. 첫 번째 항목은 그림 파일에서 중앙 위치에 대한 것으로 (X, Y) 형태이다. 두 번째는 직사각형의 (폭, 넒이)이다. 가로 길쭉과 세로 길쭉 형태를 구분하지는 않는다. 세 번째는 기울어지는 정도이다. 시계 방향이면 양수, 시계 반대 방향이면 음수인 것 같다. 나의 경우에는 폭과 넓이만 필요해서 w와 h로 결과를 받았다.

    (w, h) = rect
    [1]

    이렇게 찾은 contour가 올바른게 확인해 보려면 역시 봐야 한다. drawContours로 할 수 있다. 첫 번째는 이미지, 두번째는 좌표이다. minAreaRect로는 사각형을 그리는게 어려우니까 boxPoints로 그릴 수 있는 4개의 좌표로 변환한다. 픽셀에 소수점은 없으니까 NumPy를 이용하여 정수로 변환한다. 3번째는 첫 번째 contour를 뜻하는 0을 기술한다. 4번째는 색상이다. 추가 옵션으로 두께 같은 것이나, 모든 contour에 대한 것도 있다. 원하는 대로 잘 찾아졌는지 Pyplot으로 그려보면 된다.

    cv2.drawContours(src, [np.int64(cv2.boxPoints(rect))], 0, [255, 0, 0])
    

    분석 속도는 꽤 빠르다.