diff --git a/.ipynb_checkpoints/openCV_scanner-checkpoint.ipynb b/.ipynb_checkpoints/openCV_scanner-checkpoint.ipynb index 313abaf19e2933cc1ffc3d469befa6dd80f71245..0078e221a9b5fdb46c4f542687f327c57698b6fc 100644 --- a/.ipynb_checkpoints/openCV_scanner-checkpoint.ipynb +++ b/.ipynb_checkpoints/openCV_scanner-checkpoint.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 301, + "execution_count": 176, "metadata": { "scrolled": true }, @@ -20,90 +20,119 @@ }, { "cell_type": "code", - "execution_count": 302, + "execution_count": 177, "metadata": {}, "outputs": [], "source": [ - "def findMaxArea(contours): \n", - " max_area = -1\n", - " max_index = -1\n", - " for i,contour in enumerate(contours):\n", - " area = cv2.contourArea(contour)\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", - " return max_index" + "# 두 점 사이의 거리를 구한다.\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)))" ] }, { "cell_type": "code", - "execution_count": 303, + "execution_count": 178, "metadata": {}, "outputs": [], "source": [ - "def transform(img_input, points):\n", - " # 다음 순서롤 갖도록 꼭지점을 정렬한다.\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", - " \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]], dtype = \"float32\")\n", - " \n", - " H = cv2.getPerspectiveTransform(points, dst)\n", - " img_warped = cv2.warpPerspective(img_input, H, (maxWidth, maxHeight))\n", - " \n", - " return img_warped\n" + "# 사용자의 마우스 입력을 통하여 이미지(문서 영역)의 꼭지점을 조정하는 마우스 콜백 함수이다.\n", + "# param : event - 마우스 이벤트이다, (x, y) - 윈도우 창을 기준으로 좌측 상단점 좌표이다, \n", + "# flags - 마우스 이벤트가 발생할 때 키보드 또는 마우스 상태이다,\n", + "# param - 전달하고 싶은 데이터로 사용하지 않아도 매개변수로 받아야 한다.\n", + "# return : none\n", + "def mouse_callback(event,x,y,flags,param):\n", + " \n", + " global mouse_is_pressing, points\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", + " points[i][0] = x \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", + " # CASE 2 - 마우스 왼쪽 버튼이 눌린 상태일 때, \n", + " elif event == cv2.EVENT_LBUTTONDOWN:\n", + " # 꼭짓점과의 거리가 가깝다면 mouse_is_pressing을 True로 바꾼다. ##press 를 Ture로 바꾼다.\n", + " for point in points:\n", + " if distance((x,y), point) < 10:\n", + " mouse_is_pressing = True\n", + " break\n", + " # CASE3 - 마우스 왼쪽 버튼이 눌려있지 않으면, mouse_is_pressing을 False로 바꿈\n", + " elif event == cv2.EVENT_LBUTTONUP:\n", + "\n", + " mouse_is_pressing = False" ] }, { "cell_type": "code", - "execution_count": 304, + "execution_count": 179, "metadata": {}, "outputs": [], "source": [ + "# 두 벡터 사이의 각도를 구한다.\n", + "# param : A, B - 벡터를 표현한 ndarray이다.\n", + "# return : angle - 벡터 A와 B 사이의 각도이다.\n", + "def angle_between(A, B):\n", + "\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": 180, + "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", "\n", " points = points.astype(np.float32)\n", "\n", " new_points = np.zeros((4, 2), dtype = \"float32\")\n", " \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 = angle_between(v0, v1)\n", - "\n", + " # angle_between() : 벡터 사이의 각도를 구한다.\n", " if angle < 0:\n", " new_points[1] = points[1]\n", " new_points[3] = points[0]\n", @@ -116,76 +145,75 @@ }, { "cell_type": "code", - "execution_count": 305, - "metadata": {}, - "outputs": [], - "source": [ - "def angle_between(A, B):\n", - "\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": 306, + "execution_count": 181, "metadata": {}, "outputs": [], "source": [ - "# 마우스를 이용하여 책의 꼭지점을 조정한다.\n", - "def mouse_callback(event,x,y,flags,param):\n", - " \n", - " global mouse_is_pressing, points\n", - "\n", - " if step != 1:\n", - " return\n", - "\n", - " if event == cv2.EVENT_MOUSEMOVE: \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", - " elif event == cv2.EVENT_LBUTTONDOWN: ##마우스버튼이 눌린상태에서, 꼭짓점과의 거리가 가깝다면\n", - " ##press 를 Ture로 바꾼다.\n", - " for point in points:\n", - " if distance((x,y), point) < 10:\n", - " mouse_is_pressing = True\n", - " break\n", - "\n", - " elif event == cv2.EVENT_LBUTTONUP: ## 마우스가 안눌려있으면, press 를 false로 바꿈\n", - "\n", - " mouse_is_pressing = False" + "# 이미지(문서 영역)를 정면 방향으로 변환한다.\n", + "# param : img_input - 정면 방향으로 변환할 이미지이다, points - img_input의 꼭짓점이다.\n", + "# return : img_warped - 정면 방향으로 변환된 이미지이다.\n", + "def transform(img_input, points):\n", + " # 다음 순서롤 갖도록 꼭지점을 정렬한다.\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", + " \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]], dtype = \"float32\")\n", + " \n", + " H = cv2.getPerspectiveTransform(points, dst)\n", + " img_warped = cv2.warpPerspective(img_input, H, (maxWidth, maxHeight))\n", + " \n", + " return img_warped\n" ] }, { "cell_type": "code", - "execution_count": 307, + "execution_count": 182, "metadata": {}, "outputs": [], "source": [ - "def distance(point1, point2):\n", + "# 가장 큰 영역을 갖는 컨투어를 찾는다.\n", + "# param : contours - 컨투어들의 리스트이다.\n", + "# return : max_index - contours에서 가장 큰 영역을 갖는 컨투어의 인덱스이다.\n", + "def findMaxArea(contours): \n", + " max_area = -1\n", + " max_index = -1\n", " \n", - " x1,y1 = point1\n", - " x2,y2 = point2\n", - " \n", - " return int(np.sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2)))" + " # 가장 큰 영역을 갖는 컨투어를 찾는다.\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", + " return max_index" ] }, { "cell_type": "code", - "execution_count": 308, + "execution_count": 183, "metadata": {}, "outputs": [], "source": [ @@ -204,13 +232,14 @@ }, { "cell_type": "code", - "execution_count": 309, + "execution_count": 184, "metadata": {}, "outputs": [], "source": [ "def scanning(image):\n", " #grabcut , 배경 제거\n", " points = []\n", + "\n", " height,width =image.shape[:2]\n", " image_mask = np.zeros(image.shape[:2], np.uint8)\n", "\n", @@ -240,6 +269,9 @@ " image_canny = cv2.morphologyEx(image_canny, cv2.MORPH_CLOSE, kernel, 1)\n", " #cv2.imwrite('./modified/' +i, image_canny)\n", " #print(i + \"save image_canny!\")\n", + " global contours\n", + " global max_index\n", + " global max_contour\n", "\n", " #cv2.imshow('morphology', image_canny)\n", " #cv2.waitKey(0)\n", @@ -253,16 +285,15 @@ " image_fixed = image.copy()\n", " if max_index < 0:\n", " print(\"max_index < 0, return points \")\n", - " #print(points)\n", + " points = np.array([[10,10], [290, 10], [290, 390], [290, 390]])\n", " return points\n", "\n", + " \n", " max_contour = contours[max_index]\n", "\n", "\n", " #image_contour = image.copy()\n", " #cv2.drawContours(image_contour, [max_contour], 0, (0, 0, 255), 3)\n", - " #cv2.imwrite('./modified/' +i, image_contour)\n", - " #print(i + \"save image_contour!\")\n", " #cv2.imshow('Contour', image_contour)\n", " #cv2.waitKey(0)\n", "\n", @@ -308,7 +339,7 @@ }, { "cell_type": "code", - "execution_count": 310, + "execution_count": 185, "metadata": {}, "outputs": [], "source": [ @@ -333,12 +364,12 @@ " \n", " cv2.imshow('input', image_result)\n", " cv2.imshow('result', image_final)\n", - " cv2.imwrite('./modified/' +i, image_final)\n", + " cv2.imwrite(modified_path +i, image_final)\n", " print(i + \" i got 4 edges!!\")\n", " \n", " else:\n", " cv2.imshow('input', image)\n", - " cv2.imwrite('./modified/' +i, image)\n", + " cv2.imwrite(modified_path +i, image)\n", " print(i + \" i don't got 4 edges!\")\n", " cv2.waitKey(0)\n", " cv2.destroyAllWindows()\n", @@ -347,7 +378,7 @@ }, { "cell_type": "code", - "execution_count": 311, + "execution_count": 186, "metadata": {}, "outputs": [], "source": [ @@ -355,11 +386,11 @@ " if sizes == 4:\n", " image_final = transform(image, points)\n", " cv2.imshow('result', image_final)\n", - " cv2.imwrite('./modified/' +i, image_final)\n", + " cv2.imwrite(modified_path +i, image_final)\n", " print(i + \" i got 4 edges!!/no button\")\n", " else:\n", " cv2.imshow('input', image)\n", - " cv2.imwrite('./modified/' +i, image)\n", + " cv2.imwrite(modified_path +i, image)\n", " print(i + \" i don't got 4 edges!/no button\")\n", " cv2.waitKey(0)\n", " cv2.destroyAllWindows()\n", @@ -368,57 +399,98 @@ }, { "cell_type": "code", - "execution_count": 312, + "execution_count": 195, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "max_index < 0, return points \n", - "size 0\n", - "document.jpg i don't got 4 edges!\n", + "len of max_contour 4\n", + "size 4\n", + "[20. 39.] [213. 14.] [277. 322.] [ 76. 303.]\n", + "59.0 227.0 599.0 379.0\n", + "document.jpg i got 4 edges!!\n", + "len of max_contour 4\n", + "size 4\n", + "[36. 43.] [265. 40.] [275. 377.] [ 21. 375.]\n", + "79.0 305.0 652.0 396.0\n", + "example.jpg i got 4 edges!!\n", + "len of max_contour 4\n", + "size 4\n", + "[54. 42.] [256. 57.] [266. 347.] [ 44. 349.]\n", + "96.0 313.0 613.0 393.0\n", + "example2.jpg i got 4 edges!!\n", + "len of max_contour 4\n", + "size 4\n", + "[53. 24.] [267. 58.] [267. 379.] [ 10. 318.]\n", + "77.0 325.0 646.0 328.0\n", + "example2.png i got 4 edges!!\n", + "len of max_contour 4\n", + "size 4\n", + "[43. 30.] [263. 27.] [272. 360.] [ 52. 365.]\n", + "73.0 290.0 632.0 417.0\n", + "example3.jpg.png i got 4 edges!!\n", "len of max_contour 5\n", "size 4\n", - "[19. 70.] [121. 24.] [199. 157.] [106. 213.]\n", - "89.0 145.0 356.0 319.0\n", + "[75. 8.] [237. 11.] [229. 381.] [ 68. 377.]\n", + "83.0 248.0 610.0 445.0\n", + "receipt.jpg i got 4 edges!!\n", + "len of max_contour 4\n", + "size 4\n", + "[ 20. 100.] [152. 27.] [279. 290.] [131. 371.]\n", + "120.0 179.0 569.0 502.0\n", "receipt2.jpg i got 4 edges!!\n", "len of max_contour 8\n", "size 4\n", - "[18. 45.] [138. 32.] [158. 211.] [ 39. 225.]\n", - "63.0 170.0 369.0 264.0\n", + "[25. 73.] [208. 51.] [242. 333.] [ 60. 355.]\n", + "98.0 259.0 575.0 415.0\n", "tilted receipt.jpg i got 4 edges!!\n" ] } ], "source": [ "mouse_is_pressing = False\n", - "for i in os.listdir('./images/'): \n", - " path = './images/'+i \n", - " count = len(os.listdir('./images/'))\n", - " \n", + "image_path = './images/'\n", + "if not os.path.isdir(image_path): \n", + " os.mkdir(image_path)\n", + "\n", + "for i in os.listdir(image_path): \n", + " path = image_path + i \n", + " count = len(os.listdir(image_path))\n", " \n", + " if count == 0:\n", + " print(\"there are no images\")\n", " image = cv2.imread(path, cv2.IMREAD_COLOR)\n", - " #image=cv2.resize(image,(500,500))\n", + " image=cv2.resize(image,(300,400))\n", " points = scanning(image)\n", " sizes = len(points)\n", " print(\"size\",sizes)\n", " \n", " win = tk.Tk()\n", " win.title(\"Ask\")\n", - " win.geometry(\"500x500+50+50\")\n", + " win.geometry(\"600x600+50+50\")\n", " win.resizable(False, False)\n", "\n", " lbl = tk.Label(win, text=\"마우스 입력 O/X?\")\n", " #lbl.grid(row=1, column=1)\n", " lbl.pack()\n", + " image_contour = image.copy()\n", + " cv2.drawContours(image_contour, [max_contour], 0, (0, 0, 255), 3)\n", + " \n", + " contour_path = './contour/'\n", + " if not os.path.isdir(contour_path): \n", + " os.mkdir(contour_path)\n", + " \n", + " cv2.imwrite(contour_path +i, image_contour)\n", "\n", - " cv2.imwrite('./contours/' +i, image) \n", - "\n", - " imgtk = ImageTk.PhotoImage(file = './contours/' +i, master=win)\n", + " imgtk = ImageTk.PhotoImage(file = contour_path +i, master=win)\n", " label = tk.Label(win, image=imgtk)\n", " label.pack()\n", "\n", + " modified_path = './modified/'\n", + " if not os.path.isdir(modified_path): \n", + " os.mkdir(modified_path)\n", " b1 = tk.Button(win, text='마우스 입력O', command = b1event)\n", " b2 = tk.Button(win, text='마우스 입력X', command = b2event)\n", " #b1.grid(row=3, column=1)\n", @@ -426,75 +498,25 @@ " b1.pack()\n", " b2.pack()\n", "\n", - " win.mainloop()\n", - " \n", - " \"\"\"\n", - " size = len(points)\n", - " print(\"size\" ,size)\n", - " if size == 4:\n", - "\n", - " cv2.namedWindow('input')\n", - " cv2.setMouseCallback(\"input\", mouse_callback, 0); \n", - "\n", - "\n", - " step = 1\n", - "\n", - " # 마우스를 이용하여 꼭지점을 조정한다.\n", - " while True:\n", - "\n", - " image_result = image.copy()\n", - " for point in points:\n", - " cv2.circle(image_result, tuple(point), 10, (255,0,0), 3 ) \n", - " cv2.imshow('input', image_result)\n", - "\n", - " key = cv2.waitKey(1)\n", - " if key == 32: # 스페이스바를 누르면 선택, \n", - " break\n", - "\n", - " # 꼭지점을 이용하여 정면에서 본 책으로 변환한다.\n", - " image_final = transform(image, points )\n", - " cv2.imwrite('./modified/' +i, image_final)\n", - " print(i + \"save image_final!\")\n", - "\n", - " cv2.imshow('input', image_result)\n", - " cv2.imshow('result', image_final )\n", - " else:\n", - " cv2.imshow('input', image)\n", - " \n", - " cv2.waitKey(0)\n", - " cv2.destroyAllWindows()\n", - " win.destroy()\n", - " gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)\n", - "\n", - " sharpen = cv2.GaussianBlur(gray, (0,0), 3)\n", - " sharpen = cv2.addWeighted(gray, 1.5, sharpen, -0.5, 0)\n", - " thresh = cv2.adaptiveThreshold(sharpen, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 21, 15)\n", - " cv2.imwrite('./modified/' +i, thresh)\n", - " print(i + \" save thresh!\")\n", - " cv2.imshow('final_image', thresh)\n", - " cv2.waitKey(0)\n", - " #cv2.imwrite('./modified/' +i, modified) \n", - "\n", - " #cv2.imshow( \"image\", image)\n", - " #cv2.waitKey(0)\n", - "\n", - "\"\"\"" + " win.mainloop()" ] }, { "cell_type": "code", - "execution_count": 286, + "execution_count": 150, "metadata": {}, "outputs": [ { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'fpdf'", + "ename": "KeyboardInterrupt", + "evalue": "Interrupted by user", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m<ipython-input-286-0a916bbbf96e>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;31m#이미지 저장\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;31m##################아직 안합침################################\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[0mfpdf\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mFPDF\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 4\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mPIL\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mImage\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mos\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'fpdf'" + "\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m<ipython-input-150-0a916bbbf96e>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m 16\u001b[0m \u001b[1;31m# ------------- ADD ALL THE IMAGES IN A LIST ------------- #\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 17\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 18\u001b[1;33m \u001b[0mfolder\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0minput\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'Enter the path of the folder containing the images : '\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 19\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mdirpath\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdirnames\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfilenames\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mos\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwalk\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfolder\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 20\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mfilename\u001b[0m \u001b[1;32min\u001b[0m \u001b[1;33m[\u001b[0m\u001b[0mf\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mf\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mfilenames\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mendswith\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\".jpg\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32m~\\anaconda3\\lib\\site-packages\\ipykernel\\kernelbase.py\u001b[0m in \u001b[0;36mraw_input\u001b[1;34m(self, prompt)\u001b[0m\n\u001b[0;32m 858\u001b[0m \u001b[1;34m\"raw_input was called, but this frontend does not support input requests.\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 859\u001b[0m )\n\u001b[1;32m--> 860\u001b[1;33m return self._input_request(str(prompt),\n\u001b[0m\u001b[0;32m 861\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_parent_ident\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 862\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_parent_header\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32m~\\anaconda3\\lib\\site-packages\\ipykernel\\kernelbase.py\u001b[0m in \u001b[0;36m_input_request\u001b[1;34m(self, prompt, ident, parent, password)\u001b[0m\n\u001b[0;32m 902\u001b[0m \u001b[1;32mexcept\u001b[0m \u001b[0mKeyboardInterrupt\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 903\u001b[0m \u001b[1;31m# re-raise KeyboardInterrupt, to truncate traceback\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 904\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mKeyboardInterrupt\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Interrupted by user\"\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 905\u001b[0m \u001b[1;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 906\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlog\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwarning\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Invalid Message:\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mexc_info\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;31mKeyboardInterrupt\u001b[0m: Interrupted by user" ] } ], diff --git a/Untitled.ipynb b/Untitled.ipynb index 956cbd9b30aa743e3fea875a6b9aaffd427aae97..7fec51502cbc3200b3d0ffc6bbba1fe85e197f3d 100644 --- a/Untitled.ipynb +++ b/Untitled.ipynb @@ -1,32 +1,6 @@ { - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "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.8.5" - } - }, + "cells": [], + "metadata": {}, "nbformat": 4, "nbformat_minor": 4 } diff --git a/contour/document.jpg b/contour/document.jpg new file mode 100644 index 0000000000000000000000000000000000000000..92c30a556c2928f3e4efd2c978b81e7b55820778 Binary files /dev/null and b/contour/document.jpg differ diff --git a/contour/example.jpg b/contour/example.jpg new file mode 100644 index 0000000000000000000000000000000000000000..72c150f8d6fa32a7fbb84a078d845af0741b9d86 Binary files /dev/null and b/contour/example.jpg differ diff --git a/contour/example2.jpg b/contour/example2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9ccdd3839f35e2d836584f89f77a180489bfe387 Binary files /dev/null and b/contour/example2.jpg differ diff --git a/contour/example2.png b/contour/example2.png new file mode 100644 index 0000000000000000000000000000000000000000..7d4b700132fc604faf561ab86c6287b6df49aa75 Binary files /dev/null and b/contour/example2.png differ diff --git a/contour/example3.jpg.png b/contour/example3.jpg.png new file mode 100644 index 0000000000000000000000000000000000000000..2e015cb702f4f421399e8468c88633401a2a4b07 Binary files /dev/null and b/contour/example3.jpg.png differ diff --git a/contour/receipt.jpg b/contour/receipt.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4646e851cf72d81472874698561f5fafeed6996b Binary files /dev/null and b/contour/receipt.jpg differ diff --git a/contour/receipt2.jpg b/contour/receipt2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2ea1f5f946889225eb3e207f0323d9e8b75878d6 Binary files /dev/null and b/contour/receipt2.jpg differ diff --git a/contour/tilted receipt.jpg b/contour/tilted receipt.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3321c2e5f09b2bc1ba4df4465f954b433449f5c3 Binary files /dev/null and b/contour/tilted receipt.jpg differ diff --git a/contours/document.jpg b/contours/document.jpg deleted file mode 100644 index 062132f436d67f87ce93ba88c8515743dc6f864b..0000000000000000000000000000000000000000 Binary files a/contours/document.jpg and /dev/null differ diff --git a/contours/receipt2.jpg b/contours/receipt2.jpg deleted file mode 100644 index fae3687cc7f737191e7f9251389ce46a77b869e4..0000000000000000000000000000000000000000 Binary files a/contours/receipt2.jpg and /dev/null differ diff --git a/contours/tilted receipt.jpg b/contours/tilted receipt.jpg deleted file mode 100644 index e953c15edceab39692ef99c00df46df7b656a4a3..0000000000000000000000000000000000000000 Binary files a/contours/tilted receipt.jpg and /dev/null differ diff --git a/images/example.jpg b/images/example.jpg new file mode 100644 index 0000000000000000000000000000000000000000..83000e21df81b31b0d022818ae210b1d8f2b15e3 Binary files /dev/null and b/images/example.jpg differ diff --git a/images/example2.jpg b/images/example2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bf59c76564dc3a276adb2d4ad61c4be7b154e75d Binary files /dev/null and b/images/example2.jpg differ diff --git a/images/example2.png b/images/example2.png new file mode 100644 index 0000000000000000000000000000000000000000..1e951df84b28ca2565b268c7f977389813036035 Binary files /dev/null and b/images/example2.png differ diff --git a/images/example3.jpg.png b/images/example3.jpg.png new file mode 100644 index 0000000000000000000000000000000000000000..98f8959a3e5ae6493432b82e01d222669774cf58 Binary files /dev/null and b/images/example3.jpg.png differ diff --git a/receipt.jpg b/images/receipt.jpg similarity index 100% rename from receipt.jpg rename to images/receipt.jpg diff --git a/modified/document.jpg b/modified/document.jpg index 062132f436d67f87ce93ba88c8515743dc6f864b..51673e912e0540172bf572568c4169f2dff79228 100644 Binary files a/modified/document.jpg and b/modified/document.jpg differ diff --git a/modified/example.jpg b/modified/example.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8e7fff7894648a08ec4b58e73ce0000f843dd347 Binary files /dev/null and b/modified/example.jpg differ diff --git a/modified/example2.jpg b/modified/example2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2b0e61cf4bb7543c38d467264fd23697acfbb7ec Binary files /dev/null and b/modified/example2.jpg differ diff --git a/modified/example2.png b/modified/example2.png new file mode 100644 index 0000000000000000000000000000000000000000..146a0e9682d0ce726516b2f18890d374dcb60b14 Binary files /dev/null and b/modified/example2.png differ diff --git a/modified/example3.jpg.png b/modified/example3.jpg.png new file mode 100644 index 0000000000000000000000000000000000000000..9623dabf890feb6069b4096af081c76703b876e5 Binary files /dev/null and b/modified/example3.jpg.png differ diff --git a/modified/receipt.jpg b/modified/receipt.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1d014e9b2178d3c0539364a4be42e445f1685a41 Binary files /dev/null and b/modified/receipt.jpg differ diff --git a/modified/receipt2.jpg b/modified/receipt2.jpg index 86a073a944046fbcba804e12c7125e8d05ebd02a..7c9f8bde8e4f34e43ed1efeeb668df79b2a1bf33 100644 Binary files a/modified/receipt2.jpg and b/modified/receipt2.jpg differ diff --git a/modified/tilted receipt.jpg b/modified/tilted receipt.jpg index 2e8bc76c5dbd58373f61493124133ffbe3240f77..1df19c2cdf48f76c7a02c46a0d9b04942c3b9c0b 100644 Binary files a/modified/tilted receipt.jpg and b/modified/tilted receipt.jpg differ diff --git a/openCV_scanner.ipynb b/openCV_scanner.ipynb index 313abaf19e2933cc1ffc3d469befa6dd80f71245..43b055ca01b0690b1c8052e92c204966b5c0a468 100644 --- a/openCV_scanner.ipynb +++ b/openCV_scanner.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 301, + "execution_count": 196, "metadata": { "scrolled": true }, @@ -20,90 +20,119 @@ }, { "cell_type": "code", - "execution_count": 302, + "execution_count": 197, "metadata": {}, "outputs": [], "source": [ - "def findMaxArea(contours): \n", - " max_area = -1\n", - " max_index = -1\n", - " for i,contour in enumerate(contours):\n", - " area = cv2.contourArea(contour)\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", - " return max_index" + "# 두 점 사이의 거리를 구한다.\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)))" ] }, { "cell_type": "code", - "execution_count": 303, + "execution_count": 203, "metadata": {}, "outputs": [], "source": [ - "def transform(img_input, points):\n", - " # 다음 순서롤 갖도록 꼭지점을 정렬한다.\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", - " \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]], dtype = \"float32\")\n", - " \n", - " H = cv2.getPerspectiveTransform(points, dst)\n", - " img_warped = cv2.warpPerspective(img_input, H, (maxWidth, maxHeight))\n", - " \n", - " return img_warped\n" + "# 사용자의 마우스 입력을 통하여 이미지(문서 영역)의 꼭지점을 조정하는 마우스 콜백 함수이다.\n", + "# param : event - 마우스 이벤트이다, (x, y) - 윈도우 창을 기준으로 좌측 상단점 좌표이다, \n", + "# flags - 마우스 이벤트가 발생할 때 키보드 또는 마우스 상태이다,\n", + "# param - 전달하고 싶은 데이터로 사용하지 않아도 매개변수로 받아야 한다.\n", + "# return : none\n", + "def mouse_callback(event,x,y,flags,param):\n", + " \n", + " global mouse_is_pressing, points\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", + " points[i][0] = x \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", + " # CASE 2 - 마우스 왼쪽 버튼이 눌린 상태일 때, \n", + " elif event == cv2.EVENT_LBUTTONDOWN:\n", + " # 꼭짓점과의 거리가 가깝다면 mouse_is_pressing을 True로 바꾼다. ##press 를 Ture로 바꾼다.\n", + " for point in points:\n", + " if distance((x,y), point) < 10:\n", + " mouse_is_pressing = True\n", + " break\n", + " # CASE3 - 마우스 왼쪽 버튼이 눌려있지 않으면, mouse_is_pressing을 False로 바꿈\n", + " elif event == cv2.EVENT_LBUTTONUP:\n", + "\n", + " mouse_is_pressing = False" ] }, { "cell_type": "code", - "execution_count": 304, + "execution_count": 204, "metadata": {}, "outputs": [], "source": [ + "# 두 벡터 사이의 각도를 구한다.\n", + "# param : A, B - 벡터를 표현한 ndarray이다.\n", + "# return : angle - 벡터 A와 B 사이의 각도이다.\n", + "def angle_between(A, B):\n", + "\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": 205, + "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", "\n", " points = points.astype(np.float32)\n", "\n", " new_points = np.zeros((4, 2), dtype = \"float32\")\n", " \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 = angle_between(v0, v1)\n", - "\n", + " # angle_between() : 벡터 사이의 각도를 구한다.\n", " if angle < 0:\n", " new_points[1] = points[1]\n", " new_points[3] = points[0]\n", @@ -116,76 +145,75 @@ }, { "cell_type": "code", - "execution_count": 305, - "metadata": {}, - "outputs": [], - "source": [ - "def angle_between(A, B):\n", - "\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": 306, + "execution_count": 206, "metadata": {}, "outputs": [], "source": [ - "# 마우스를 이용하여 책의 꼭지점을 조정한다.\n", - "def mouse_callback(event,x,y,flags,param):\n", - " \n", - " global mouse_is_pressing, points\n", - "\n", - " if step != 1:\n", - " return\n", - "\n", - " if event == cv2.EVENT_MOUSEMOVE: \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", - " elif event == cv2.EVENT_LBUTTONDOWN: ##마우스버튼이 눌린상태에서, 꼭짓점과의 거리가 가깝다면\n", - " ##press 를 Ture로 바꾼다.\n", - " for point in points:\n", - " if distance((x,y), point) < 10:\n", - " mouse_is_pressing = True\n", - " break\n", - "\n", - " elif event == cv2.EVENT_LBUTTONUP: ## 마우스가 안눌려있으면, press 를 false로 바꿈\n", - "\n", - " mouse_is_pressing = False" + "# 이미지(문서 영역)를 정면 방향으로 변환한다.\n", + "# param : img_input - 정면 방향으로 변환할 이미지이다, points - img_input의 꼭짓점이다.\n", + "# return : img_warped - 정면 방향으로 변환된 이미지이다.\n", + "def transform(img_input, points):\n", + " # 다음 순서롤 갖도록 꼭지점을 정렬한다.\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", + " \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]], dtype = \"float32\")\n", + " \n", + " H = cv2.getPerspectiveTransform(points, dst)\n", + " img_warped = cv2.warpPerspective(img_input, H, (maxWidth, maxHeight))\n", + " \n", + " return img_warped\n" ] }, { "cell_type": "code", - "execution_count": 307, + "execution_count": 207, "metadata": {}, "outputs": [], "source": [ - "def distance(point1, point2):\n", + "# 가장 큰 영역을 갖는 컨투어를 찾는다.\n", + "# param : contours - 컨투어들의 리스트이다.\n", + "# return : max_index - contours에서 가장 큰 영역을 갖는 컨투어의 인덱스이다.\n", + "def findMaxArea(contours): \n", + " max_area = -1\n", + " max_index = -1\n", " \n", - " x1,y1 = point1\n", - " x2,y2 = point2\n", - " \n", - " return int(np.sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2)))" + " # 가장 큰 영역을 갖는 컨투어를 찾는다.\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", + " return max_index" ] }, { "cell_type": "code", - "execution_count": 308, + "execution_count": 208, "metadata": {}, "outputs": [], "source": [ @@ -204,13 +232,14 @@ }, { "cell_type": "code", - "execution_count": 309, + "execution_count": 209, "metadata": {}, "outputs": [], "source": [ "def scanning(image):\n", " #grabcut , 배경 제거\n", " points = []\n", + "\n", " height,width =image.shape[:2]\n", " image_mask = np.zeros(image.shape[:2], np.uint8)\n", "\n", @@ -240,6 +269,9 @@ " image_canny = cv2.morphologyEx(image_canny, cv2.MORPH_CLOSE, kernel, 1)\n", " #cv2.imwrite('./modified/' +i, image_canny)\n", " #print(i + \"save image_canny!\")\n", + " global contours\n", + " global max_index\n", + " global max_contour\n", "\n", " #cv2.imshow('morphology', image_canny)\n", " #cv2.waitKey(0)\n", @@ -253,16 +285,15 @@ " image_fixed = image.copy()\n", " if max_index < 0:\n", " print(\"max_index < 0, return points \")\n", - " #print(points)\n", + " points = np.array([[10,10], [290, 10], [290, 390], [290, 390]])\n", " return points\n", "\n", + " \n", " max_contour = contours[max_index]\n", "\n", "\n", " #image_contour = image.copy()\n", " #cv2.drawContours(image_contour, [max_contour], 0, (0, 0, 255), 3)\n", - " #cv2.imwrite('./modified/' +i, image_contour)\n", - " #print(i + \"save image_contour!\")\n", " #cv2.imshow('Contour', image_contour)\n", " #cv2.waitKey(0)\n", "\n", @@ -308,7 +339,7 @@ }, { "cell_type": "code", - "execution_count": 310, + "execution_count": 210, "metadata": {}, "outputs": [], "source": [ @@ -333,12 +364,12 @@ " \n", " cv2.imshow('input', image_result)\n", " cv2.imshow('result', image_final)\n", - " cv2.imwrite('./modified/' +i, image_final)\n", + " cv2.imwrite(modified_path +i, image_final)\n", " print(i + \" i got 4 edges!!\")\n", " \n", " else:\n", " cv2.imshow('input', image)\n", - " cv2.imwrite('./modified/' +i, image)\n", + " cv2.imwrite(modified_path +i, image)\n", " print(i + \" i don't got 4 edges!\")\n", " cv2.waitKey(0)\n", " cv2.destroyAllWindows()\n", @@ -347,7 +378,7 @@ }, { "cell_type": "code", - "execution_count": 311, + "execution_count": 211, "metadata": {}, "outputs": [], "source": [ @@ -355,11 +386,11 @@ " if sizes == 4:\n", " image_final = transform(image, points)\n", " cv2.imshow('result', image_final)\n", - " cv2.imwrite('./modified/' +i, image_final)\n", + " cv2.imwrite(modified_path +i, image_final)\n", " print(i + \" i got 4 edges!!/no button\")\n", " else:\n", " cv2.imshow('input', image)\n", - " cv2.imwrite('./modified/' +i, image)\n", + " cv2.imwrite(modified_path +i, image)\n", " print(i + \" i don't got 4 edges!/no button\")\n", " cv2.waitKey(0)\n", " cv2.destroyAllWindows()\n", @@ -368,57 +399,98 @@ }, { "cell_type": "code", - "execution_count": 312, + "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "max_index < 0, return points \n", - "size 0\n", - "document.jpg i don't got 4 edges!\n", - "len of max_contour 5\n", + "len of max_contour 4\n", + "size 4\n", + "[20. 39.] [213. 14.] [277. 322.] [ 76. 303.]\n", + "59.0 227.0 599.0 379.0\n", + "document.jpg i got 4 edges!!\n", + "len of max_contour 4\n", + "size 4\n", + "[36. 43.] [265. 40.] [274. 369.] [ 21. 375.]\n", + "79.0 305.0 643.0 396.0\n", + "example.jpg i got 4 edges!!\n", + "len of max_contour 4\n", + "size 4\n", + "[54. 42.] [256. 57.] [266. 347.] [ 44. 349.]\n", + "96.0 313.0 613.0 393.0\n", + "example2.jpg i got 4 edges!!\n", + "len of max_contour 4\n", + "size 4\n", + "[53. 24.] [267. 58.] [267. 379.] [ 10. 318.]\n", + "77.0 325.0 646.0 328.0\n", + "example2.png i got 4 edges!!\n", + "len of max_contour 4\n", + "size 4\n", + "[43. 30.] [263. 27.] [272. 360.] [ 52. 365.]\n", + "73.0 290.0 632.0 417.0\n", + "example3.jpg.png i got 4 edges!!\n", + "len of max_contour 7\n", + "size 4\n", + "[74. 9.] [273. 8.] [275. 376.] [ 77. 378.]\n", + "83.0 281.0 651.0 455.0\n", + "receipt.jpg i got 4 edges!!\n", + "len of max_contour 4\n", "size 4\n", - "[19. 70.] [121. 24.] [199. 157.] [106. 213.]\n", - "89.0 145.0 356.0 319.0\n", + "[ 20. 100.] [152. 27.] [279. 290.] [131. 371.]\n", + "120.0 179.0 569.0 502.0\n", "receipt2.jpg i got 4 edges!!\n", "len of max_contour 8\n", "size 4\n", - "[18. 45.] [138. 32.] [158. 211.] [ 39. 225.]\n", - "63.0 170.0 369.0 264.0\n", + "[25. 74.] [208. 51.] [243. 334.] [ 60. 357.]\n", + "99.0 259.0 577.0 417.0\n", "tilted receipt.jpg i got 4 edges!!\n" ] } ], "source": [ "mouse_is_pressing = False\n", - "for i in os.listdir('./images/'): \n", - " path = './images/'+i \n", - " count = len(os.listdir('./images/'))\n", - " \n", + "image_path = './images/'\n", + "if not os.path.isdir(image_path): \n", + " os.mkdir(image_path)\n", + "\n", + "for i in os.listdir(image_path): \n", + " path = image_path + i \n", + " count = len(os.listdir(image_path))\n", " \n", + " if count == 0:\n", + " print(\"there are no images\")\n", " image = cv2.imread(path, cv2.IMREAD_COLOR)\n", - " #image=cv2.resize(image,(500,500))\n", + " image=cv2.resize(image,(300,400))\n", " points = scanning(image)\n", " sizes = len(points)\n", " print(\"size\",sizes)\n", " \n", " win = tk.Tk()\n", " win.title(\"Ask\")\n", - " win.geometry(\"500x500+50+50\")\n", + " win.geometry(\"600x600+50+50\")\n", " win.resizable(False, False)\n", "\n", " lbl = tk.Label(win, text=\"마우스 입력 O/X?\")\n", " #lbl.grid(row=1, column=1)\n", " lbl.pack()\n", + " image_contour = image.copy()\n", + " cv2.drawContours(image_contour, [max_contour], 0, (0, 0, 255), 3)\n", + " \n", + " contour_path = './contour/'\n", + " if not os.path.isdir(contour_path): \n", + " os.mkdir(contour_path)\n", + " \n", + " cv2.imwrite(contour_path +i, image_contour)\n", "\n", - " cv2.imwrite('./contours/' +i, image) \n", - "\n", - " imgtk = ImageTk.PhotoImage(file = './contours/' +i, master=win)\n", + " imgtk = ImageTk.PhotoImage(file = contour_path +i, master=win)\n", " label = tk.Label(win, image=imgtk)\n", " label.pack()\n", "\n", + " modified_path = './modified/'\n", + " if not os.path.isdir(modified_path): \n", + " os.mkdir(modified_path)\n", " b1 = tk.Button(win, text='마우스 입력O', command = b1event)\n", " b2 = tk.Button(win, text='마우스 입력X', command = b2event)\n", " #b1.grid(row=3, column=1)\n", @@ -426,75 +498,25 @@ " b1.pack()\n", " b2.pack()\n", "\n", - " win.mainloop()\n", - " \n", - " \"\"\"\n", - " size = len(points)\n", - " print(\"size\" ,size)\n", - " if size == 4:\n", - "\n", - " cv2.namedWindow('input')\n", - " cv2.setMouseCallback(\"input\", mouse_callback, 0); \n", - "\n", - "\n", - " step = 1\n", - "\n", - " # 마우스를 이용하여 꼭지점을 조정한다.\n", - " while True:\n", - "\n", - " image_result = image.copy()\n", - " for point in points:\n", - " cv2.circle(image_result, tuple(point), 10, (255,0,0), 3 ) \n", - " cv2.imshow('input', image_result)\n", - "\n", - " key = cv2.waitKey(1)\n", - " if key == 32: # 스페이스바를 누르면 선택, \n", - " break\n", - "\n", - " # 꼭지점을 이용하여 정면에서 본 책으로 변환한다.\n", - " image_final = transform(image, points )\n", - " cv2.imwrite('./modified/' +i, image_final)\n", - " print(i + \"save image_final!\")\n", - "\n", - " cv2.imshow('input', image_result)\n", - " cv2.imshow('result', image_final )\n", - " else:\n", - " cv2.imshow('input', image)\n", - " \n", - " cv2.waitKey(0)\n", - " cv2.destroyAllWindows()\n", - " win.destroy()\n", - " gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)\n", - "\n", - " sharpen = cv2.GaussianBlur(gray, (0,0), 3)\n", - " sharpen = cv2.addWeighted(gray, 1.5, sharpen, -0.5, 0)\n", - " thresh = cv2.adaptiveThreshold(sharpen, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 21, 15)\n", - " cv2.imwrite('./modified/' +i, thresh)\n", - " print(i + \" save thresh!\")\n", - " cv2.imshow('final_image', thresh)\n", - " cv2.waitKey(0)\n", - " #cv2.imwrite('./modified/' +i, modified) \n", - "\n", - " #cv2.imshow( \"image\", image)\n", - " #cv2.waitKey(0)\n", - "\n", - "\"\"\"" + " win.mainloop()" ] }, { "cell_type": "code", - "execution_count": 286, + "execution_count": 150, "metadata": {}, "outputs": [ { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'fpdf'", + "ename": "KeyboardInterrupt", + "evalue": "Interrupted by user", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m<ipython-input-286-0a916bbbf96e>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;31m#이미지 저장\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;31m##################아직 안합침################################\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[0mfpdf\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mFPDF\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 4\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mPIL\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mImage\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mos\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'fpdf'" + "\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m<ipython-input-150-0a916bbbf96e>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m 16\u001b[0m \u001b[1;31m# ------------- ADD ALL THE IMAGES IN A LIST ------------- #\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 17\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 18\u001b[1;33m \u001b[0mfolder\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0minput\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'Enter the path of the folder containing the images : '\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 19\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mdirpath\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdirnames\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfilenames\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mos\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwalk\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfolder\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 20\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mfilename\u001b[0m \u001b[1;32min\u001b[0m \u001b[1;33m[\u001b[0m\u001b[0mf\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mf\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mfilenames\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mendswith\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\".jpg\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32m~\\anaconda3\\lib\\site-packages\\ipykernel\\kernelbase.py\u001b[0m in \u001b[0;36mraw_input\u001b[1;34m(self, prompt)\u001b[0m\n\u001b[0;32m 858\u001b[0m \u001b[1;34m\"raw_input was called, but this frontend does not support input requests.\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 859\u001b[0m )\n\u001b[1;32m--> 860\u001b[1;33m return self._input_request(str(prompt),\n\u001b[0m\u001b[0;32m 861\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_parent_ident\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 862\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_parent_header\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32m~\\anaconda3\\lib\\site-packages\\ipykernel\\kernelbase.py\u001b[0m in \u001b[0;36m_input_request\u001b[1;34m(self, prompt, ident, parent, password)\u001b[0m\n\u001b[0;32m 902\u001b[0m \u001b[1;32mexcept\u001b[0m \u001b[0mKeyboardInterrupt\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 903\u001b[0m \u001b[1;31m# re-raise KeyboardInterrupt, to truncate traceback\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 904\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mKeyboardInterrupt\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Interrupted by user\"\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 905\u001b[0m \u001b[1;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 906\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlog\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwarning\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Invalid Message:\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mexc_info\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;31mKeyboardInterrupt\u001b[0m: Interrupted by user" ] } ],