diff --git a/comment.ipynb b/comment.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..f735848bf2e01ecd660aa2ef858f5f79810a29b5 --- /dev/null +++ b/comment.ipynb @@ -0,0 +1,225 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "solved-logan", + "metadata": {}, + "outputs": [], + "source": [ + "# 가장 큰 영역을 갖는 컨투어를 찾는다.\n", + "# param : contours - 컨투어들의 리스트이다.\n", + "# return : max_index - contours에서 가장 큰 영역을 갖는 컨투어의 인덱스이다.\n", + "def findMaxArea(contours):\n", + " max_area = -1\n", + " max_index = -1\n", + " \n", + " # 가장 큰 영역을 갖는 컨투어를 찾는다.\n", + " for i,contour in enumerate(contours):\n", + " # cv2.contourArea : 컨투어의 넓이를 얻는다.\n", + " area = cv2.contourArea(contour) \n", + " # cv.boundingRect : 컨투어 라인을 둘러싸는 사각형을 그린다.\n", + " x,y,w,h = cv2.boundingRect(contour)\n", + " if (w*h)*0.4 > area:\n", + " continue\n", + " if w > h:\n", + " continue\n", + " if area > max_area:\n", + " max_area = area\n", + " max_index = i \n", + " if max_area < 10000:\n", + " max_index = -1\n", + " \n", + " return max_index" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "parental-police", + "metadata": {}, + "outputs": [], + "source": [ + "# 이미지(문서 영역)를 정면 방향으로 변환한다.\n", + "# param : img_input - 정면 방향으로 변환할 이미지이다, points - img_input의 꼭짓점이다.\n", + "# return : img_warped - 정면 방향으로 변환된 이미지이다.\n", + "def transform(img_input, points):\n", + " # sort_points(): 다음 순서를 갖도록 꼭지점을 정렬한다.\n", + " # top left, top right, bottom right, bottom left\n", + " points = sort_points(points)\n", + " topLeft, topRight, bottomRight, bottomLeft = points\n", + " print(topLeft, topRight, bottomRight, bottomLeft)\n", + " print(topLeft[0] + topLeft[1], topRight[0]+topRight[1],\n", + " bottomRight[0]+bottomRight[1], bottomLeft[0]+bottomLeft[1])\n", + " \n", + " # 변환 후, 이미지(문서 영역)의 너비와 높이를 결정한다.\n", + " topWidth = distance(bottomLeft, bottomRight)\n", + " bottomWidth = distance(topLeft, topRight)\n", + " maxWidth = max(int(topWidth), int(bottomWidth))\n", + " leftHeight = distance(topLeft, bottomLeft)\n", + " rightHeight = distance(topRight, bottomRight)\n", + " maxHeight = max(int(leftHeight), int(rightHeight))\n", + " \n", + " # 정면 방향의 이미지(문서 영역)의 좌표를 결정한다.\n", + " dst = np.array([[0, 0],[maxWidth - 1, 0],\n", + " [maxWidth - 1, maxHeight - 1],[0, maxHeight - 1]], \n", + " dtype = \"float32\")\n", + " \n", + " # 정면 방향의 이미지(문서 영역)로 변환한다.\n", + " H = cv2.getPerspectiveTransform(points, dst)\n", + " img_warped = cv2.warpPerspective(img_input, H, (maxWidth, maxHeight))\n", + " \n", + " return img_warped" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "stupid-playback", + "metadata": {}, + "outputs": [], + "source": [ + "# 다음 순서를 갖도록 꼭짓점을 정렬한다.\n", + "# top left, top right, bottom right, bottom left\n", + "# param : points - 정렬되기 전의 꼭짓점의 ndarray이다.\n", + "# return : new_points - 정렬된 후의 꼭짓점의 ndarray이다.\n", + "def sort_points(points):\n", + " points = points.astype(np.float32)\n", + " new_points = np.zeros((4, 2), dtype = \"float32\")\n", + " \n", + " # top left를 구한다.\n", + " s = points.sum(axis = 1)\n", + " min_index = np.argmin(s)\n", + " new_points[0] = points[min_index]\n", + " points = np.delete(points, min_index, axis = 0)\n", + " \n", + " # bottom right를 구한다.\n", + " s = points.sum(axis = 1)\n", + " max_index = np.argmax(s)\n", + " new_points[2] = points[max_index]\n", + " points = np.delete(points, max_index, axis = 0)\n", + "\n", + " # top right, bottom left를 구한다.\n", + " v0 = points[0] - new_points[0]\n", + " v1 = points[1] - new_points[0]\n", + " \n", + " # angle_between() : 벡터 사이의 각도를 구한다.\n", + " angle = angle_between(v0, v1)\n", + " if angle < 0:\n", + " new_points[1] = points[1]\n", + " new_points[3] = points[0]\n", + " else:\n", + " new_points[1] = points[0]\n", + " new_points[3] = points[1]\n", + " \n", + " return new_points" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "antique-acrobat", + "metadata": {}, + "outputs": [], + "source": [ + "# 두 벡터 사이의 각도를 구한다.\n", + "# param : A, B - 벡터를 표현한 ndarray이다.\n", + "# return : angle - 벡터 A와 B 사이의 각도이다.\n", + "def angle_between(A, B):\n", + " x1 = A[0]\n", + " y1 = A[1]\n", + " x2 = B[0]\n", + " y2 = B[1]\n", + "\n", + " dot = x1*x2 + y1*y2 \n", + " det = x1*y2 - y1*x2\n", + " angle = np.arctan2(det, dot) * 180/np.pi \n", + "\n", + " return angle" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ambient-canberra", + "metadata": {}, + "outputs": [], + "source": [ + "# 사용자의 마우스 입력을 통하여 이미지(문서 영역)의 꼭지점을 조정하는 마우스 콜백 함수이다.\n", + "# param : event - 마우스 이벤트이다, (x, y) - 윈도우 창을 기준으로 좌측 상단점 좌표이다, \n", + "# flags - 마우스 이벤트가 발생할 때 키보드 또는 마우스 상태이다,\n", + "# param - 전달하고 싶은 데이터로 사용하지 않아도 매개변수로 받아야 한다.\n", + "# return : none\n", + "def mouse_callback(event, x ,y, flags, param):\n", + " global mouse_is_pressing, points\n", + " \n", + " # step == 1 이면,마우스 콜백 함수가 등록된 것이다.\n", + " # step != 1 이면, cv2.setMouseCallback()을 통해 마우스 콜백 함수가 등록되지 않은 것이다.\n", + " if step != 1:\n", + " return\n", + "\n", + " # CASE 1 - 마우스가 움직이고\n", + " if event == cv2.EVENT_MOUSEMOVE: \n", + " # 눌린 상태일 때,\n", + " if mouse_is_pressing == True: \n", + " # 마우스의 좌표와, 포인트(꼭짓점)의 거리가 가깝다면, 꼭지점을 이동한다.\n", + " for i,point in enumerate(points):\n", + " if distance((x,y), point) < 15: \n", + " points[i][0] = x \n", + " points[i][1] = y\n", + " break\n", + " \n", + " # CASE 2 - 마우스 왼쪽 버튼이 눌린 상태일 때, ` \n", + " elif event == cv2.EVENT_LBUTTONDOWN: \n", + " # 꼭짓점과의 거리가 가깝다면 mouse_is_pressing을 True로 바꾼다.\n", + " for point in points:\n", + " if distance((x,y), point) < 10:\n", + " mouse_is_pressing = True\n", + " break\n", + " \n", + " # CASE3 - 마우스 왼쪽 버튼이 눌려있지 않으면, mouse_is_pressing을 False로 바꿈\n", + " elif event == cv2.EVENT_LBUTTONUP: \n", + " mouse_is_pressing = False" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "circular-clear", + "metadata": {}, + "outputs": [], + "source": [ + "# 두 점 사이의 거리를 구한다.\n", + "# param : point1, point2 - 거리를 구할 두 점이다.\n", + "# return : point1, point2 사이의 거리이다.\n", + "def distance(point1, point2):\n", + " \n", + " x1, y1 = point1\n", + " x2, y2 = point2\n", + " \n", + " return int(np.sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2)))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.1" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}