Deskew using Hough Lines
First implementation finished. Working on using it to crop. Going to try using probabalistic hough lines and a bounding box to pick out lines within a margin of the correct orientation (vertical) and put a bounding box around these lines to try and approximate the receipt. Signed-off-by: Ethan Wellenreiter <ewellenreiter@gmail.com>
This commit is contained in:
parent
f66a757d8b
commit
d5e7a2eed2
@ -2,7 +2,7 @@
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 59,
|
||||
"execution_count": 264,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -13,18 +13,20 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 60,
|
||||
"execution_count": 265,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import cv2\n",
|
||||
"import numpy as np\n",
|
||||
"import math"
|
||||
"import math\n",
|
||||
"\n",
|
||||
"import scipy.stats as st"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 61,
|
||||
"execution_count": 266,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -59,40 +61,62 @@
|
||||
" hp = int((max_wh - w) / 2)\n",
|
||||
" vp = int((max_wh - h) / 2)\n",
|
||||
" padding = (hp, vp, hp, vp)\n",
|
||||
" return cv2.copyMakeBorder(image, vp, vp, hp, hp, cv2.BORDER_CONSTANT, self.fill)"
|
||||
" return cv2.copyMakeBorder(image, vp, vp, hp, hp, cv2.BORDER_CONSTANT, self.fill)\n",
|
||||
" \n",
|
||||
" \n",
|
||||
" \n",
|
||||
"def rotate(img, angle):\n",
|
||||
" rows,cols = img.shape[0], img.shape[1]\n",
|
||||
" M = cv2.getRotationMatrix2D((cols/2,rows/2),angle,1)\n",
|
||||
" dst = cv2.warpAffine(img,M,(cols,rows))\n",
|
||||
" return dst"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 62,
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"img = cv2.imread('./testing_space/final.jpg')"
|
||||
"def WithinXDegrees(lines, margin):\n",
|
||||
" for line in lines:\n",
|
||||
" if ()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 63,
|
||||
"execution_count": 267,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"img = ResizeWithAspectRatio(SquarePad(fill=255)(img), 500)\n",
|
||||
"img = cv2.imread('./testing_space/final.jpg')\n",
|
||||
"img = SquarePad(fill=255)(img)\n",
|
||||
"img = rotate(img, 54)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 268,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"resizedimg = ResizeWithAspectRatio(SquarePad(fill=255)(img), 500)\n",
|
||||
"\n",
|
||||
"cv2.imshow(\"Detected Lines (in red) - Standard Hough Line Transform\", img)\n",
|
||||
"cv2.waitKey(0)\n",
|
||||
"cv2.destroyAllWindows()\n",
|
||||
"# cv2.imshow(\"Detected Lines (in red) - Standard Hough Line Transform\", img)\n",
|
||||
"# cv2.waitKey(0)\n",
|
||||
"# cv2.destroyAllWindows()\n",
|
||||
"\n",
|
||||
"gray = cv2.cvtColor(resizedimg ,cv2.COLOR_BGR2GRAY)\n",
|
||||
"cdst = resizedimg.copy()\n",
|
||||
"\n",
|
||||
"gray = cv2.cvtColor(img ,cv2.COLOR_BGR2GRAY)\n",
|
||||
"cdst = img.copy()\n",
|
||||
"\n",
|
||||
"dst = cv2.Canny(gray, 50, 200, None, 3)\n",
|
||||
"lines = cv2.HoughLines(dst, 1, np.pi/180, 100, None, 0, 0)\n"
|
||||
"lines = cv2.HoughLines(dst, 1, np.pi/180, 150, None, 0, 0)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 64,
|
||||
"execution_count": 269,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -105,31 +129,133 @@
|
||||
" b = math.sin(theta)\n",
|
||||
" x0 = a * rho\n",
|
||||
" y0 = b * rho\n",
|
||||
" pt1 = (int(x0 + 1000*(-b)), int(y0 + 1000*(a)))\n",
|
||||
" pt2 = (int(x0 - 1000*(-b)), int(y0 - 1000*(a)))\n",
|
||||
" unroundedpt1 = (x0 + 1000*(-b), y0 + 1000*(a))\n",
|
||||
" unroundedpt2 = (x0 - 1000*(-b), y0 - 1000*(a))\n",
|
||||
" pt1 = (int(unroundedpt1[0]), int(unroundedpt1[1]))\n",
|
||||
" pt2 = (int(unroundedpt2[0]), int(unroundedpt2[1]))\n",
|
||||
" v1_theta = math.atan2(pt1[1], pt1[0])\n",
|
||||
" v2_theta = math.atan2(v2[1], v2[0])\n",
|
||||
" angles[i] = ((v2_theta - v1_theta) * (180.0 / math.pi)) % 360\n",
|
||||
" v2_theta = math.atan2(pt2[1], pt2[0])\n",
|
||||
" angles[i] = abs(math.atan2(unroundedpt2[1] - unroundedpt1[1], unroundedpt2[0] - unroundedpt1[0]))\n",
|
||||
" cv2.line(cdst, pt1, pt2, (0,0,255), 3, cv2.LINE_AA)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 270,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"34.95042550298022\n",
|
||||
"-55.04957449701978\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# print(st.mode(np.around(angles, decimals=1)))\n",
|
||||
"mode = st.mode(np.around(angles, decimals=2))[0]\n",
|
||||
"print(np.rad2deg(mode))\n",
|
||||
"# slope = math.tan(np.deg2rad(mode))\n",
|
||||
"# print(slope)\n",
|
||||
"# myy0 = 0\n",
|
||||
"# p1 = [0,myy0]\n",
|
||||
"# p2 = [0,myy0]\n",
|
||||
"# while (math.dist(p1, p2) < 5000):\n",
|
||||
"# p2[0] += 0.5\n",
|
||||
"# p2[1] += 0.5*slope*1000\n",
|
||||
"# p2[1] = int(p2[1])\n",
|
||||
"# print(p2)\n",
|
||||
"# cv2.line(cdst, p1, p2, (0,255,0), 3, cv2.LINE_AA)\n",
|
||||
"rotationangle = np.rad2deg(mode)-90\n",
|
||||
"print(rotationangle)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 271,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"cv2.imshow(\"Detected Lines (in red) - Standard Hough Line Transform\", cdst)\n",
|
||||
"cv2.waitKey(0)\n",
|
||||
"cv2.destroyAllWindows()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 272,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"cv2.imshow(\"Detected Lines (in red) - Standard Hough Line Transform\", rotate(cdst,rotationangle))\n",
|
||||
"cv2.waitKey(0)\n",
|
||||
"cv2.destroyAllWindows()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 273,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"rotatedimg = SquarePad(fill=255)(rotate(img, rotationangle))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 274,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"cv2.imshow(\"Rotated Image\", ResizeWithAspectRatio(rotatedimg, 1000))\n",
|
||||
"cv2.waitKey(0)\n",
|
||||
"cv2.destroyAllWindows()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 302,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"resizedrotatedimg = ResizeWithAspectRatio(rotatedimg, 500)\n",
|
||||
"gray1 = cv2.cvtColor(resizedrotatedimg, cv2.COLOR_BGR2GRAY)\n",
|
||||
"dst1 = cv2.Canny(gray1, 50, 200, None, 3)\n",
|
||||
"cdstP = resizedrotatedimg.copy()\n",
|
||||
"linesP = cv2.HoughLinesP(dst1, 1, np.pi / 180, 50, None, 50, 30)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 303,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if linesP is not None:\n",
|
||||
" for i in range(0, len(linesP)):\n",
|
||||
" l = linesP[i][0]\n",
|
||||
" cv2.line(cdstP, (l[0], l[1]), (l[2], l[3]), (0,0,255), 3, cv2.LINE_AA)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 305,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"cv2.imshow(\"Detected Lines (in red) - Standard Hough Line Transform\", cdstP)\n",
|
||||
"cv2.waitKey(0)\n",
|
||||
"cv2.destroyAllWindows()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 65,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"cv2.imshow(\"Detected Lines (in red) - Standard Hough Line Transform\", cdst)\n",
|
||||
"cv2.waitKey(0)\n",
|
||||
"cv2.destroyAllWindows()"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
@ -2,9 +2,20 @@
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 154,
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"/usr/local/lib/python3.10/dist-packages/torchvision/datapoints/__init__.py:12: UserWarning: The torchvision.datapoints and torchvision.transforms.v2 namespaces are still Beta. While we do not expect major breaking changes, some APIs may still change according to user feedback. Please submit any feedback you may have in this issue: https://github.com/pytorch/vision/issues/6753, and you can also check out https://github.com/pytorch/vision/issues/7319 to learn more about the APIs that we suspect might involve future changes. You can silence this warning by calling torchvision.disable_beta_transforms_warning().\n",
|
||||
" warnings.warn(_BETA_TRANSFORMS_WARNING)\n",
|
||||
"/usr/local/lib/python3.10/dist-packages/torchvision/transforms/v2/__init__.py:54: UserWarning: The torchvision.datapoints and torchvision.transforms.v2 namespaces are still Beta. While we do not expect major breaking changes, some APIs may still change according to user feedback. Please submit any feedback you may have in this issue: https://github.com/pytorch/vision/issues/6753, and you can also check out https://github.com/pytorch/vision/issues/7319 to learn more about the APIs that we suspect might involve future changes. You can silence this warning by calling torchvision.disable_beta_transforms_warning().\n",
|
||||
" warnings.warn(_BETA_TRANSFORMS_WARNING)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import cv2\n",
|
||||
"import numpy as np\n",
|
||||
@ -17,7 +28,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 155,
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -46,7 +57,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 156,
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -67,7 +78,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 157,
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -96,7 +107,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 158,
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -171,7 +182,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 159,
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -188,7 +199,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 160,
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -198,7 +209,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 161,
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -245,7 +256,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 162,
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -299,7 +310,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 163,
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -326,7 +337,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 164,
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -349,7 +360,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 165,
|
||||
"execution_count": 12,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -377,7 +388,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 166,
|
||||
"execution_count": 13,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -386,7 +397,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 169,
|
||||
"execution_count": 15,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
@ -395,24 +406,24 @@
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 169,
|
||||
"execution_count": 15,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"cropped = morphologyCrop(img)\n",
|
||||
"rotated = deskew(cropped)\n",
|
||||
"cropped2 = morphologyCrop(rotated)\n",
|
||||
"# rotated = deskew(cropped)\n",
|
||||
"# cropped2 = morphologyCrop(rotated)\n",
|
||||
"# cropped2 = selectiveSearchCrop(rotated)\n",
|
||||
"# cropped3 = cannyEdgeCrop(cropped2)\n",
|
||||
"cv2.imwrite(\"./testing_space/final.jpg\", cropped2)\n",
|
||||
"cv2.imwrite(\"./testing_space/final.jpg\", cropped)\n",
|
||||
"# final = rotate(cropped2, 180) # need to implement the code to determine if a doc is upside down"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 168,
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
||||
Loading…
Reference in New Issue
Block a user