이미지 분석을 통해 골 연령을 산출하여 성장 과정 동안의 키 성장을 예측
이번 프로젝트에서는 골연령을 예측하는 것이 목표
각 이미지마다 크기가 다르기 때문에 이미지 크기를 동일하게 설정
# 전체 이미지의 비율 평균 계산하여 resize 할 비율 결정
ratio = 0
for i in range(len(total_df.id)):
img = cv2.imread(total_path + total_df['id'][i], cv2.IMREAD_GRAYSCALE)
ratio += img.shape[0] / img.shape[1]
ratio / len(total_df.id) ## 1.266
# 이미지 사이즈 재설정
img = cv2.imread(total_path + '98.jpg', cv2.IMREAD_GRAYSCALE)
resize_img = cv2.resize(img, (800, 1000))
# 이미지 min max 정규화
normal_img = cv2.normalize(resize_img, None, 0, 255, cv2.NORM_MINMAX)
createCLAHE(Contrast Limited Adaptive Histogram Equalization)
이미지를 여러 작은 블록으로 나누어 각 블록에 대해 독립적으로 히스토그램 평탄화를 적용
clahe = cv2.createCLAHE(clipLimit=1, tileGridSize=(3,3))
equal_img=clahe.apply(denoise_img)
0(검은색), 255(흰색)로 이진화
r_img = np.copy(temp_img)
height, width = temp_img.shape
img = temp_img[0:(int)(height*0.9),0:(int)(width*0.95)]
# 픽셀 값의 평균 크면 255로 설정되고 작으면 0으로 설정정
ret, img = cv2.threshold(img, temp_img.mean(), 255, cv2.THRESH_BINARY)
#샘플 이미지 Thresholding 결과
plt.imshow(img,"gray")
객체의 윤곽선 추출
contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
#외곽선 검출하여 mask 그리기
max_cnt = max(contours, key=cv2.contourArea)
mask = np.zeros(img.shape, dtype=np.uint8)
cv2.drawContours(mask, [max_cnt], -1, (255,255,255), -1)
plt.imshow(mask, 'gray')
y좌표 기준으로 첫 번째 흰색 좌표가 중지 끝부분임
M = cv2.moments(max_cnt)
center = (int(M['m10']/M['m00']), int(M['m01']/M['m00']))
for y,x_r in enumerate(mask) :
if 255 in x_r:
#y에 따른 x rows 중 255인 x값 추출
x_255_indexs = np.where(x_r == 255)[0]
#255인 x값들 중 median 추출
x_255_mid_index = x_255_indexs[len(x_255_indexs)//2]
first_255_x_point = x_255_mid_index
first_255_y_point = y
break
(first_255_x_point,first_255_y_point) # (298, 102)
# 이미지 회전 함수 정의
def rotate_image(image, angle):
image_center = tuple(np.array(image.shape[1::-1]) / 2)
rot_mat = cv2.getRotationMatrix2D(image_center, angle, 1.0)
result = cv2.warpAffine(image, rot_mat, image.shape[1::-1], flags=cv2.INTER_LINEAR,borderValue=(255,255,255))
return result
# 무게중심과 첫 흰색 좌표 차이
center_x, center_y = center[0], center[1]
rx = abs(first_255_x_point - center_x)
ry = center_y - first_255_y_point
# 회전 각도 구하기
import math
radian = math.atan2(ry, rx)
degree = 90 - math.degrees(radian)
# 무게중심과 첫 좌표 위치에 따라 회전 방향 조정
if first_255_x_point < center_x :
mask = rotate_image(mask,360-degree)
r_img_ = rotate_image(temp_img,360-degree)
else:
mask = rotate_image(mask,degree)
r_img_ = rotate_image(temp_img,degree)
cv2.convexHull, cv2.convexityDefects 를 이용해 오목한 부분의 좌표를 구하여 좌료로써 ROI 추출을 진행한다.
자세한 부분은 image_roi.ipynb 참고
현재 데이터가 1234개로 학습하기에는 데이터가 부족함
데이터 증강을 통해 학습시의 과적합을 방지하고 좀 더 유연한 모델을 만들어본다.
아래 논문 참고하여 모델을 생성하였음
Intelligent Bone Age Assessment: An Automated System to Detect a Bone Growth Problem Using Convolutional Neural Networks with Attention Mechanism
위 사진은 사용할 모델의 구성으로 input 으로 4차원 tensor, output 값은 1개이다.
loss 는 mae로 회귀로 학습한다.
crop 이미지를 thresholding 여부로 실험 -> 이진화처리를 하지 않는게 더 정확도가 높음
배치사이즈는 본인의 메모리에 따라 다르게 진행하는데 작을수록 더 정확했음
데이터 증강하여 학습 데이터에 추가하였더니 정확도가 1.11 에서 0.78까지 상승
최종적으로 mae : 0.785 으로 약 9.43 months 오차발생
앞선 논문에 대한 실험 결과인데 논문 결과로는 약 7.7 months 오차가 발생하였다.
위 논문에서는 TW3 방식으로 관절의 ROI 추출과 정제된 X-ray 데이터 14235개의 데이터로 진행하였는데,
이 프로젝트는 TW3 와 같은 의학 부분의 전문적인 지식없이 ROI 추출하였고, 데이터의 개수도 1236개로 진행하였음
그 부분을 감안하였을 때 9.43months 의 오차는 허용범위라고 판단하여 프로젝트를 종료하기로 결정