diff --git a/.ipynb_checkpoints/openCV_scanner-checkpoint.ipynb b/.ipynb_checkpoints/openCV_scanner-checkpoint.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..bd154fb26b8e208c3292ca4c933e6a6d5a462e2b --- /dev/null +++ b/.ipynb_checkpoints/openCV_scanner-checkpoint.ipynb @@ -0,0 +1,438 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 54, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import cv2\n", + "import glob\n", + "from matplotlib import pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "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" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "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" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [], + "source": [ + "def sort_points(points):\n", + "\n", + " points = points.astype(np.float32)\n", + "\n", + " new_points = np.zeros((4, 2), dtype = \"float32\")\n", + " \n", + "\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", + " 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", + " v0 = points[0] - new_points[0]\n", + " v1 = points[1] - new_points[0]\n", + "\n", + " angle = angle_between(v0, v1)\n", + "\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": 58, + "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": 59, + "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" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [], + "source": [ + "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": 67, + "metadata": {}, + "outputs": [], + "source": [ + "def scanning(image):\n", + " #grabcut , 배경 제거\n", + " points = []\n", + " height,width =image.shape[:2]\n", + " image_mask = np.zeros(image.shape[:2], np.uint8)\n", + "\n", + " bgdModel = np.zeros((1,65),np.float64)\n", + " fgdModel = np.zeros((1,65),np.float64)\n", + "\n", + " rect = (10,10,width-30,height-30)\n", + " cv2.grabCut(image, image_mask, rect, bgdModel,fgdModel, 3, cv2.GC_INIT_WITH_RECT)\n", + "\n", + " image_mask = np.where((image_mask==2)|(image_mask==0), 0, 1).astype('uint8')\n", + " image_grabcut = image*image_mask[:,:,np.newaxis]\n", + "\n", + " #cv2.imshow('grabCut', image_grabcut)\n", + " #cv2.waitKey(0)\n", + " \n", + " #케니에지 디텍션을 이용하여 에지 검출\n", + " image_gray = cv2.cvtColor(image_grabcut, cv2.COLOR_BGR2GRAY);\n", + " image_canny = cv2.Canny(image_gray, 30, 90);\n", + "\n", + "\n", + " #cv2.imshow('Canny', image_canny)\n", + " #cv2.waitKey(0)\n", + "\n", + " #모폴로지 클로즈 연산\n", + "\n", + " kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))\n", + " 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", + "\n", + " cv2.imshow('morphology', image_canny)\n", + " cv2.waitKey(0)\n", + " # 캐니 에지 결과에서 컨투어를 검출하여 가장 큰 영역을 차지하는 컨투어를 찾는다.\n", + " contours, hierarchy = cv2.findContours(image_canny, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)\n", + " max_index = findMaxArea(contours) \n", + " \n", + " \"\"\"\n", + " #################이부분이 잘 이해가 안감.\n", + " if max_index < 0:\n", + " print(\"max_index < 0 \" +i)\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", + " # approxPolyDP 함수를 사용하여 컨투어를 근사화하고 convex hull을 구한다.\n", + " max_contour = cv2.approxPolyDP(max_contour,0.02*cv2.arcLength(max_contour,True),True)\n", + " hull = cv2.convexHull(max_contour)\n", + "\n", + "\n", + " image_convexhull = image.copy()\n", + " cv2.drawContours(image_convexhull, [hull], 0, (255,255,0), 5)\n", + " cv2.imwrite('./modified/' +i, image_convexhull) \n", + " print(i + \"save image_convexhull!\")\n", + " cv2.imshow('convexHull', image_convexhull)\n", + " cv2.waitKey(0)\n", + " \n", + " size = len(max_contour) \n", + " print(size)\n", + " if size == 4: # 책의 꼭지점을 구한다.\n", + " for c in hull:\n", + " points.append(c[0])\n", + " points = np.array(points)\n", + " print(points)\n", + "\n", + " else: # 꼭지점이 5개 이상인 경우 경계 박스를 이용한다.\n", + "\n", + " rect = cv2.minAreaRect(hull)\n", + " box = cv2.boxPoints(rect)\n", + " points = np.int0(box.tolist())\n", + "\n", + " # 검출된 꼭지점이 이미지 범위를 벗어난 경우 책 꼭지점 처리\n", + " found = False\n", + " for p in points:\n", + " if p[0] < 0 or p[0] > width-1 or p[1] < 0 or p[1] > height -1:\n", + " found = True \n", + " break\n", + "\n", + " if found:\n", + " points = np.array([[10,10], [width-11, 10], [width-11, height-11], [10, height-11]])\n", + " return points\n", + "\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "book.jpgsave image_canny!\n", + "book.jpgsave image_contour!\n", + "book.jpgsave image_convexhull!\n", + "7\n", + "[10. 10.] [489. 10.] [489. 489.] [ 10. 489.]\n", + "20.0 499.0 978.0 499.0\n", + "book.jpgsave image_final!\n", + "book.jpg save thresh!\n", + "book2.jpgsave image_canny!\n", + "book2.jpgsave image_contour!\n", + "book2.jpgsave image_convexhull!\n", + "6\n", + "[10. 10.] [489. 10.] [489. 489.] [ 10. 489.]\n", + "20.0 499.0 978.0 499.0\n", + "book2.jpgsave image_final!\n", + "book2.jpg save thresh!\n", + "receipt2.jpgsave image_canny!\n", + "receipt2.jpgsave image_contour!\n", + "receipt2.jpgsave image_convexhull!\n", + "4\n", + "[[465 362]\n", + " [203 463]\n", + " [ 34 125]\n", + " [254 34]]\n", + "[ 34. 125.] [254. 34.] [465. 362.] [203. 463.]\n", + "159.0 288.0 827.0 666.0\n", + "receipt2.jpgsave image_final!\n", + "receipt2.jpg save thresh!\n" + ] + } + ], + "source": [ + "######################################################################\n", + "#이미지파일 한번에 여러개 받는 방법??\n", + "#\n", + "#\n", + "import os\n", + "for i in os.listdir('./images/'): \n", + " path = './images/'+i \n", + " count = len(os.listdir('./images/'))\n", + " \n", + " \n", + " image = cv2.imread(path, cv2.IMREAD_COLOR)\n", + " image=cv2.resize(image,(500,500))\n", + " points = scanning(image)\n", + " \n", + " size = len(points)\n", + " if size == 4:\n", + "\n", + " ##############################################################\n", + " # 여기에 사용자가 마우스 사용할지 안할지에대한 GUI 넣기?\n", + " # \n", + " #\n", + " #\n", + " ####################################################################\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", + "\n", + " else:\n", + " cv2.imshow('input', image)\n", + " \n", + " cv2.waitKey(0)\n", + " cv2.destroyAllWindows()\n", + " #cv2.imwrite('./modified/' +i, image_final) \n", + " ################################################################\n", + " ############영수증의 경우 이것을 사용하면 글씨가 돋보임 ( 흑백대비)\n", + " gray = cv2.cvtColor(image_final, 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('grayscale?', thresh)\n", + " cv2.waitKey(0)\n", + " #cv2.imwrite('./modified/' +i, modified) \n", + "\n", + " #cv2.imshow( \"image\", image)\n", + " #cv2.waitKey(0)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 231, + "metadata": {}, + "outputs": [], + "source": [ + "#이미지 저장\n", + "def save(image):\n", + " cv2.imwrite('./modified/modified.jpg', image) \n" + ] + }, + { + "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" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/images/receipt.jpg b/images/receipt.jpg deleted file mode 100644 index 6a1fea89295717a2dc66f273876b1f6e79f98053..0000000000000000000000000000000000000000 Binary files a/images/receipt.jpg and /dev/null differ diff --git a/modified/book.jpg b/modified/book.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4a59aeb1fcd68e9ff12973ade5669be3060fad3b Binary files /dev/null and b/modified/book.jpg differ diff --git a/modified/book2.jpg b/modified/book2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7670c878737ae5168a9ee21fb81893da51829485 Binary files /dev/null and b/modified/book2.jpg differ diff --git a/modified/modified.jpg b/modified/modified.jpg deleted file mode 100644 index 6380610691871f1e8cac343bc0c0ce2e38c198bf..0000000000000000000000000000000000000000 Binary files a/modified/modified.jpg and /dev/null differ diff --git a/modified/receipt2.jpg b/modified/receipt2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e9a428cc4f6f8b851b4d9567d46a9178ebb8cc60 Binary files /dev/null and b/modified/receipt2.jpg differ diff --git a/openCV_scanner.ipynb b/openCV_scanner.ipynb index ad83d382691c5e317746743f63454d40bc7ec7fb..bd154fb26b8e208c3292ca4c933e6a6d5a462e2b 100644 --- a/openCV_scanner.ipynb +++ b/openCV_scanner.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 78, + "execution_count": 54, "metadata": { "scrolled": true }, @@ -16,7 +16,7 @@ }, { "cell_type": "code", - "execution_count": 79, + "execution_count": 55, "metadata": {}, "outputs": [], "source": [ @@ -40,7 +40,7 @@ }, { "cell_type": "code", - "execution_count": 80, + "execution_count": 56, "metadata": {}, "outputs": [], "source": [ @@ -74,7 +74,7 @@ }, { "cell_type": "code", - "execution_count": 81, + "execution_count": 57, "metadata": {}, "outputs": [], "source": [ @@ -112,7 +112,7 @@ }, { "cell_type": "code", - "execution_count": 82, + "execution_count": 58, "metadata": {}, "outputs": [], "source": [ @@ -132,7 +132,7 @@ }, { "cell_type": "code", - "execution_count": 83, + "execution_count": 59, "metadata": {}, "outputs": [], "source": [ @@ -167,7 +167,7 @@ }, { "cell_type": "code", - "execution_count": 84, + "execution_count": 60, "metadata": {}, "outputs": [], "source": [ @@ -181,247 +181,93 @@ }, { "cell_type": "code", - "execution_count": 96, + "execution_count": 67, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"\\ncv2.imshow('images',image)\\ncv2.waitKey(0)\\n\"" - ] - }, - "execution_count": 96, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "image = cv2.imread('./images/receipt.jpg') \n", + "def scanning(image):\n", + " #grabcut , 배경 제거\n", + " points = []\n", + " height,width =image.shape[:2]\n", + " image_mask = np.zeros(image.shape[:2], np.uint8)\n", "\n", - "# rgb 이미지 보기\n", - "\"\"\"\n", - "cv2.imshow('images',image)\n", - "cv2.waitKey(0)\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": 97, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"\\npath = 'C:/Users/User/Desktop/opencv/images' # 폴더 경로\\nos.chdir(path) # 해당 폴더로 이동\\n\\nfiles = os.listdir(path) # 해당 폴더에 있는 파일 이름을 리스트 형태로 받음\\npng_img = []\\njpg_img = []\\nfor file in files:\\n if '.png' in file: \\n f = cv2.imread(file)\\n png_img.append(f)\\n if '.jpg' in file: \\n f = cv2.imread(file)\\n jpg_img.append(f)\\n\"" - ] - }, - "execution_count": 97, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "######################################################################\n", - "#이미지파일 한번에 여러개 받는 방법??\n", - "#\n", - "#\n", - "\"\"\"\n", - "path = 'C:/Users/User/Desktop/opencv/images' # 폴더 경로\n", - "os.chdir(path) # 해당 폴더로 이동\n", - "\n", - "files = os.listdir(path) # 해당 폴더에 있는 파일 이름을 리스트 형태로 받음\n", - "png_img = []\n", - "jpg_img = []\n", - "for file in files:\n", - " if '.png' in file: \n", - " f = cv2.imread(file)\n", - " png_img.append(f)\n", - " if '.jpg' in file: \n", - " f = cv2.imread(file)\n", - " jpg_img.append(f)\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": 98, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"\\ncv2.imshow('grabCut', image_grabcut)\\ncv2.waitKey(0)\\n\"" - ] - }, - "execution_count": 98, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "#grabcut , 배경 제거\n", - "points = []\n", - "height,width =image.shape[:2]\n", - "image_mask = np.zeros(image.shape[:2], np.uint8)\n", - "\n", - "bgdModel = np.zeros((1,65),np.float64)\n", - "fgdModel = np.zeros((1,65),np.float64)\n", - "\n", - "rect = (10,10,width-30,height-30)\n", - "cv2.grabCut(image, image_mask, rect, bgdModel,fgdModel, 3, cv2.GC_INIT_WITH_RECT)\n", - "\n", - "image_mask = np.where((image_mask==2)|(image_mask==0), 0, 1).astype('uint8')\n", - "image_grabcut = image*image_mask[:,:,np.newaxis]\n", - "\"\"\"\n", - "cv2.imshow('grabCut', image_grabcut)\n", - "cv2.waitKey(0)\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": 109, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "-1" - ] - }, - "execution_count": 109, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "#케니에지 디텍션을 이용하여 에지 검출\n", - "image_gray = cv2.cvtColor(image_grabcut, cv2.COLOR_BGR2GRAY);\n", - "image_canny = cv2.Canny(image_gray, 30, 90);\n", - "\n", - "\"\"\"\n", - "cv2.imshow('Canny', image_canny)\n", - "cv2.waitKey(0)\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": 110, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "-1" - ] - }, - "execution_count": 110, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "#모폴로지 클로즈 연산\n", + " bgdModel = np.zeros((1,65),np.float64)\n", + " fgdModel = np.zeros((1,65),np.float64)\n", "\n", - "kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))\n", - "image_canny = cv2.morphologyEx(image_canny, cv2.MORPH_CLOSE, kernel, 1)\n", + " rect = (10,10,width-30,height-30)\n", + " cv2.grabCut(image, image_mask, rect, bgdModel,fgdModel, 3, cv2.GC_INIT_WITH_RECT)\n", "\n", - "\"\"\"\n", - "cv2.imshow('morphology', image_canny)\n", - "cv2.waitKey(0)\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": 101, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"\\nimage_contour = image.copy()\\ncv2.drawContours(image_contour, [max_contour], 0, (0, 0, 255), 3)\\ncv2.imshow('Contour', image_contour)\\ncv2.waitKey(0)\\n\"" - ] - }, - "execution_count": 101, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# 캐니 에지 결과에서 컨투어를 검출하여 가장 큰 영역을 차지하는 컨투어를 찾는다.\n", - "contours, hierarchy = cv2.findContours(image_canny, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)\n", - "max_index = findMaxArea(contours) \n", - "\"\"\"\n", - "if max_index < 0:\n", - " return points\n", - "\"\"\"\n", - "if max_index < 0:\n", - " print(points)\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.imshow('Contour', image_contour)\n", - "cv2.waitKey(0)\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": 111, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "-1" - ] - }, - "execution_count": 111, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# approxPolyDP 함수를 사용하여 컨투어를 근사화하고 convex hull을 구한다.\n", - "max_contour = cv2.approxPolyDP(max_contour,0.02*cv2.arcLength(max_contour,True),True)\n", - "hull = cv2.convexHull(max_contour)\n", - "\n", - "\"\"\"\n", - "img_convexhull = image.copy()\n", - "cv2.drawContours(img_convexhull, [hull], 0, (255,255,0), 5)\n", - "cv2.imshow('convexHull', img_convexhull)\n", - "cv2.waitKey(0)\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": 103, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "size = len(max_contour) \n", + " image_mask = np.where((image_mask==2)|(image_mask==0), 0, 1).astype('uint8')\n", + " image_grabcut = image*image_mask[:,:,np.newaxis]\n", "\n", - "if size == 4: # 책의 꼭지점을 구한다.\n", - " for c in hull:\n", - " points.append(c[0])\n", - " points = np.array(points)\n", - " print(points)\n", + " #cv2.imshow('grabCut', image_grabcut)\n", + " #cv2.waitKey(0)\n", + " \n", + " #케니에지 디텍션을 이용하여 에지 검출\n", + " image_gray = cv2.cvtColor(image_grabcut, cv2.COLOR_BGR2GRAY);\n", + " image_canny = cv2.Canny(image_gray, 30, 90);\n", + "\n", + "\n", + " #cv2.imshow('Canny', image_canny)\n", + " #cv2.waitKey(0)\n", + "\n", + " #모폴로지 클로즈 연산\n", + "\n", + " kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))\n", + " 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", + "\n", + " cv2.imshow('morphology', image_canny)\n", + " cv2.waitKey(0)\n", + " # 캐니 에지 결과에서 컨투어를 검출하여 가장 큰 영역을 차지하는 컨투어를 찾는다.\n", + " contours, hierarchy = cv2.findContours(image_canny, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)\n", + " max_index = findMaxArea(contours) \n", + " \n", + " \"\"\"\n", + " #################이부분이 잘 이해가 안감.\n", + " if max_index < 0:\n", + " print(\"max_index < 0 \" +i)\n", + " return points\n", + " \"\"\"\n", "\n", - "else: # 꼭지점이 5개 이상인 경우 경계 박스를 이용한다.\n", - " \n", - " rect = cv2.minAreaRect(hull)\n", - " box = cv2.boxPoints(rect)\n", - " points = np.int0(box.tolist())\n", + " max_contour = contours[max_index]\n", "\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", + " # approxPolyDP 함수를 사용하여 컨투어를 근사화하고 convex hull을 구한다.\n", + " max_contour = cv2.approxPolyDP(max_contour,0.02*cv2.arcLength(max_contour,True),True)\n", + " hull = cv2.convexHull(max_contour)\n", + "\n", + "\n", + " image_convexhull = image.copy()\n", + " cv2.drawContours(image_convexhull, [hull], 0, (255,255,0), 5)\n", + " cv2.imwrite('./modified/' +i, image_convexhull) \n", + " print(i + \"save image_convexhull!\")\n", + " cv2.imshow('convexHull', image_convexhull)\n", + " cv2.waitKey(0)\n", + " \n", + " size = len(max_contour) \n", + " print(size)\n", + " if size == 4: # 책의 꼭지점을 구한다.\n", + " for c in hull:\n", + " points.append(c[0])\n", + " points = np.array(points)\n", + " print(points)\n", + "\n", + " else: # 꼭지점이 5개 이상인 경우 경계 박스를 이용한다.\n", + "\n", + " rect = cv2.minAreaRect(hull)\n", + " box = cv2.boxPoints(rect)\n", + " points = np.int0(box.tolist())\n", + "\n", + " # 검출된 꼭지점이 이미지 범위를 벗어난 경우 책 꼭지점 처리\n", " found = False\n", " for p in points:\n", " if p[0] < 0 or p[0] > width-1 or p[1] < 0 or p[1] > height -1:\n", @@ -430,159 +276,134 @@ "\n", " if found:\n", " points = np.array([[10,10], [width-11, 10], [width-11, height-11], [10, height-11]])\n", - " \"\"\"\n", " return points\n", - " \"\"\"" + "\n", + " " ] }, { "cell_type": "code", - "execution_count": 104, + "execution_count": 68, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[66. 24.] [1428. 10.] [1428. 1041.] [ 10. 1041.]\n", - "90.0 1438.0 2469.0 1051.0\n", - "END\n" + "book.jpgsave image_canny!\n", + "book.jpgsave image_contour!\n", + "book.jpgsave image_convexhull!\n", + "7\n", + "[10. 10.] [489. 10.] [489. 489.] [ 10. 489.]\n", + "20.0 499.0 978.0 499.0\n", + "book.jpgsave image_final!\n", + "book.jpg save thresh!\n", + "book2.jpgsave image_canny!\n", + "book2.jpgsave image_contour!\n", + "book2.jpgsave image_convexhull!\n", + "6\n", + "[10. 10.] [489. 10.] [489. 489.] [ 10. 489.]\n", + "20.0 499.0 978.0 499.0\n", + "book2.jpgsave image_final!\n", + "book2.jpg save thresh!\n", + "receipt2.jpgsave image_canny!\n", + "receipt2.jpgsave image_contour!\n", + "receipt2.jpgsave image_convexhull!\n", + "4\n", + "[[465 362]\n", + " [203 463]\n", + " [ 34 125]\n", + " [254 34]]\n", + "[ 34. 125.] [254. 34.] [465. 362.] [203. 463.]\n", + "159.0 288.0 827.0 666.0\n", + "receipt2.jpgsave image_final!\n", + "receipt2.jpg save thresh!\n" ] } ], "source": [ - "size = len(points)\n", - "if size == 4:\n", - "\n", - "##############################################################\n", - "# 여기에 사용자가 마우스 사용할지 안할지에대한 GUI 넣기?\n", - "# \n", + "######################################################################\n", + "#이미지파일 한번에 여러개 받는 방법??\n", "#\n", "#\n", - "####################################################################\n", - " # 마우스 콜백 함수를 등록하고\n", - " cv2.namedWindow('input')\n", - " cv2.setMouseCallback(\"input\", mouse_callback, 0); \n", + "import os\n", + "for i in os.listdir('./images/'): \n", + " path = './images/'+i \n", + " count = len(os.listdir('./images/'))\n", + " \n", + " \n", + " image = cv2.imread(path, cv2.IMREAD_COLOR)\n", + " image=cv2.resize(image,(500,500))\n", + " points = scanning(image)\n", + " \n", + " size = len(points)\n", + " if size == 4:\n", "\n", + " ##############################################################\n", + " # 여기에 사용자가 마우스 사용할지 안할지에대한 GUI 넣기?\n", + " # \n", + " #\n", + " #\n", + " ####################################################################\n", + " # 마우스 콜백 함수를 등록하고\n", + " cv2.namedWindow('input')\n", + " cv2.setMouseCallback(\"input\", mouse_callback, 0); \n", "\n", - " step = 1\n", "\n", - " # 마우스를 이용하여 꼭지점을 조정한다.\n", - " while True:\n", + " step = 1\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", + " while True:\n", "\n", - " # 꼭지점을 이용하여 정면에서 본 책으로 변환한다.\n", - " image_final = transform(image, points )\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", - " cv2.imshow('input', image_result)\n", - " cv2.imshow('result', image_final )\n", - " \n", - " print(\"END\")\n", + " # 꼭지점을 이용하여 정면에서 본 책으로 변환한다.\n", + " image_final = transform(image, points )\n", + " cv2.imwrite('./modified/' +i, image_final)\n", + " print(i + \"save image_final!\")\n", "\n", - "else:\n", - " cv2.imshow('input', image)\n", + " cv2.imshow('input', image_result)\n", + " cv2.imshow('result', image_final )\n", "\n", - "cv2.waitKey(0)\n", - "cv2.destroyAllWindows()" - ] - }, - { - "cell_type": "code", - "execution_count": 105, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "-1" - ] - }, - "execution_count": 105, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "################################################################\n", - "############영수증의 경우 이것을 사용하면 글씨가 돋보임 ( 흑백대비)\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.imshow('grayscale?', thresh)\n", - "cv2.waitKey(0)" - ] - }, - { - "cell_type": "code", - "execution_count": 106, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 106, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cv2.imwrite('C:/Users/User/Desktop/opencv/modified/modified.jpg', image_final) \n", - "#이미지 저장" + " else:\n", + " cv2.imshow('input', image)\n", + " \n", + " cv2.waitKey(0)\n", + " cv2.destroyAllWindows()\n", + " #cv2.imwrite('./modified/' +i, image_final) \n", + " ################################################################\n", + " ############영수증의 경우 이것을 사용하면 글씨가 돋보임 ( 흑백대비)\n", + " gray = cv2.cvtColor(image_final, 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('grayscale?', thresh)\n", + " cv2.waitKey(0)\n", + " #cv2.imwrite('./modified/' +i, modified) \n", + "\n", + " #cv2.imshow( \"image\", image)\n", + " #cv2.waitKey(0)\n" ] }, { "cell_type": "code", - "execution_count": 107, + "execution_count": 231, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"\\nimport cv2\\nimage = cv2.imread('./images/book.jpg') \\n\\n# rgb 이미지 보기\\ncv2.imshow('images',image) \\ncv2.resizeWindow('images', 600, 600)\\ncv2.waitKey(0)\\ndef onMouse(event, x, y, flags, param): # 아무스 콜백 함수 구현 ---①\\n print(event, x, y, ) # 파라미터 출력\\n if event == cv2.EVENT_LBUTTONDOWN: # 왼쪽 버튼 누름인 경우 ---②\\n cv2.circle(image, (x,y), 30, (0,0,0), -1) # 지름 30 크기의 검은색 원을 해당 좌표에 그림\\n cv2.imshow(images, image) # 그려진 이미지를 다시 표시 ---③\\ncv2.setMouseCallback(images, onMouse) # 마우스 콜백 함수를 GUI 윈도우에 등록 ---④\\n\"" - ] - }, - "execution_count": 107, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "\"\"\"\n", - "import cv2\n", - "image = cv2.imread('./images/book.jpg') \n", - "\n", - "# rgb 이미지 보기\n", - "cv2.imshow('images',image) \n", - "cv2.resizeWindow('images', 600, 600)\n", - "cv2.waitKey(0)\n", - "def onMouse(event, x, y, flags, param): # 아무스 콜백 함수 구현 ---①\n", - " print(event, x, y, ) # 파라미터 출력\n", - " if event == cv2.EVENT_LBUTTONDOWN: # 왼쪽 버튼 누름인 경우 ---②\n", - " cv2.circle(image, (x,y), 30, (0,0,0), -1) # 지름 30 크기의 검은색 원을 해당 좌표에 그림\n", - " cv2.imshow(images, image) # 그려진 이미지를 다시 표시 ---③\n", - "cv2.setMouseCallback(images, onMouse) # 마우스 콜백 함수를 GUI 윈도우에 등록 ---④\n", - "\"\"\"\n", - "\n", - "######################################################################################################\n", - "# 추가로 해야할것 :\n", - "# 1. 마우스 입력을 받을때와 안받을때 구분짓기\n", - "# 2. 폴더채로 이미지파일 받아와서 한번에 처리하기.\n", - "# 3. 흑백 색 강조하여 이미지 깔끔하게 만들기\n", - "# 4. 파일 저장형식을 사용자가 원하는대로 만들기" + "#이미지 저장\n", + "def save(image):\n", + " cv2.imwrite('./modified/modified.jpg', image) \n" ] }, {