졸업프로젝트_스마트팜

[졸업프로젝트] Smart farm using Drone an AI : Grape berry counting & Grading

미미수 2022. 5. 17. 19:02

안녕하세요 오늘은 요즘 진행중인 졸업프로젝트에 관해서 포스팅하려 합니다.

 

프로젝트는 기술적으로 4가지 파트로 나뉩니다.

AI, Drone, Front/Backend.

그 중에서도 제가 맡은 AI부분에 집중해서 설명해보도록 하겠습니다.

 

1. 왜 포도인가요?

많고 많은 작물,과수 중에 포도를 선택한 이유는, 가장 노동집약적인 작물이라고 판단했기 때문입니다.

포도의 특성상,

- 대규모 농가의 비율이 큼(와이너리)

- 세계적으로 재배되는 작물

- 재배에 인간의 노하우가 많이 필요함 -> 노동자의 숙련도가 중요하다.

 

대규모 농가에서 노동자의 숙련도가 필요한 작업을 하려면 비용이 올라가고, 작업이 연장됩니다.

한정된 인원으로 제공할수 있는 노동력또한 한정적이기 때문이지요. 결과적으로 비용이 증가하고 품질관리가 미흡해지는 단점이 존재합니다.

이때 스마트팜 시스템을 도입해 노동 집약적인 부분을 제거해주면, 품질이 올라가고 비용이 감소한다는 것!

특히 포도의 경우 포도알 솎아내기라는 작업이 1년에 1~2회로 품질관리에 필수적인데, 작업이 필요한 구역에서만 솎아낸다면 그 넓은 밭을 헤집고 다니지 않아도 됩니다.

 

2. 왜 드론인가요?

드론은 보급이 쉽고, 인간이 조종할수도, 자율주행을 시킬수도 있으며, 소프트웨어만 잘 탑재하면 별도로 하드웨어 개발이 필요 없었기 때문에 드론을 선택하였습니다. 

 

 


AI가 제공하는 정보는 크게 3가지입니다. 

 

1. 포도 생산량

2. 포도알의 개수

3. 포도 등급

 


 

1. Grape Detection

드론으로 촬영한 포도밭 영상을 input으로 받으면 그 안에서 포도를 detection합니다.

GPS가 탑재되어 있는 드론이라면 정확한 구역까지 제공할 수 있겠지만, GPS가 없는 드론이기 때문에,

드론의 속도와 드론이동 경로로 위치를 측정하였습니다.

 

이렇게 bounding box를 구한 후, 포도를 crop해 다음 모델에 넘겨줄 준비를 합니다.

 

2. Grape berry segmentation

 

Grape berry는 레이블링된 open dataset이 없었기 때문에, 최대한 작은 데이터셋으로 최대의 효율을 내는 모델을 찾고자 습니다.

그 중 Boxinst라는 모델이 데이터 레이블링을 박스로만 해줘도 됐기 총 150장 정도로 학습을 진행했고 결과는 위와 같습니다.

 

Instance segmentation단계에서는 모든 포도의 마스크를 구하고, 불량 포도알정상 포도알, 두가지 class로 구분합니다.

다음단계에는 detectron의 GenericMask라는 class를 압축해 넘겨줍니다.

 

3. Feature Extraction

고용량의 마스크들을 전부 받은건 다 이유가 있습니다.

가장 중요한 feature extraction을 진행하기 위해서 인데요.

Feature extraction은 주로 opencv와 수학 공식들을 활용해 작성되었습니다.

그 중 몇가지를 선정해 코드와 같이 설명하겠습니다.

 

[ Circularity ]

각각의 포도알의 원형을 띌수록 포도알이 가려지지 않았다고 볼 수 있습니다.

가려진 포도알들은 그 윤곽이 울퉁불퉁합니다.

def circularity(self,area,parameter):
        cir = (4*3.14*area)/(parameter*parameter)
        if cir < 0.7:
            return 0 #원이 아님
        else:
            return 1 #원에 가까움

 

[ 넓이, 지름, 종횡비 ] 

넓이와 지름은 포도 이미지에서 포도가 얼마나 close-up돼서 촬영됐는지를 알 수 있는 지표로 사용됩니다.

def area(self, contour):
    return cv2.contourArea(contour)
    
def perimeter(self,contour):
    return cv2.arcLength(contour,True)
    
def aspect_ratio(self,contour): #종횡비
    x,t,w,h = cv2.boundingRect(contour)
    return float(x)/h

 

[ 색상 ]

각 포도알의 Hue를 뽑아 낸후, 전체 포도알 색조의 균일도를 구해 포도 등급을 매길때 사용합니다.

def hue_extraction(self,contours):
        img = cv2.imread(self.image_path)
        hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
        hue = hsv[:,:,0]
        lower_range = np.array([75, 50, 50])
        upper_range = np.array([165, 200, 255])
        thresh = cv2.inRange(hsv, lower_range, upper_range)
        N2=0
        count = img.copy()
        cv2.drawContours(count, contours, 0, (100, 0, 255), 2)
        mask = np.zeros_like(thresh, dtype=np.uint8)
        cv2.drawContours(mask, contours, 0, (255,255,255), -1)
        ave_hue = np.mean(hue[np.where(mask==255)])
        return ave_hue

 

이 외에도 여러가지 지표가 있고, 이 지표들을 회귀분석 데이터로 사용해 총 포도알의 개수를 예측하고, 등급을 매기는데 사용합니다.

 

4. Random Forest Regression

마지막으로 구한 지표, 이미지에서 detect한 포도알의 개수를 종합해 총 포도알의 개수를 구합니다.

한장의 2D 이미지에서는 가려진 포도알의 개수를 에측할 수 없습니다.

3D모델링을 사용하거나 적어도 2개의 pointview에서 촬영한 이미지가 있어야 합니다.

 

포도송이의 밀집도, 각 알들의 occlusion rate, 이미지에서 count한 포도알의 개수 등을 사용해 회귀분석하면 8개의 포도알 오차범위 이내에 약 89%의 정확도로 포도알의 개수를 예측할 수 있습니다.