├── LICENSE ├── README.md ├── Scanner.py ├── mapper.py └── test_img.jpg /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CamScanner-In-Python 2 | Build your own document scanner with OpenCV Python 3 | 4 | Video DEMO and TUTORIAL : https://www.youtube.com/watch?v=PV0uxIfy_-A 5 | 6 | ## What is this ? 7 | The script takes an image as input and then scans the document from the image by applying few image processing techniques and gives the output image with scanned effect 8 | 9 | ## How does it do this? 10 | Initially we need to resize the images so OpenCV can handle it and then the following functions are applied 11 | 1) Guassian Blur to smoothen image. 12 | 2) Canny Edges to detect the edges. 13 | 3) Find contours and boundary of the page 14 | 4) Map the end points of contours to 800 * 800 window 15 | 5) Apply perspective trasform to get scanned or bird eye view of the image. 16 | 17 | ## This is shit, why did you build this? 18 | I was BORED :/ 19 | 20 | # Installation 21 | ``` 22 | pip install opencv-python 23 | ``` 24 | 25 | ## Credits 26 | 27 | 1) Guassian Blur : https://docs.opencv.org/3.1.0/d4/d13/tutorial_py_filtering.html 28 | 2) SO article on guassian Blur https://computergraphics.stackexchange.com/questions/39/how-is-gaussian-blur-implemented 29 | 3) Vipul Sharma Github : https://github.com/vipul-sharma20/document-scanner 30 | 4) Canny Edge Deetction https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_canny/py_canny.html 31 | 5)Contours Documentation : https://docs.opencv.org/3.1.0/d4/d73/tutorial_py_contours_begin.html 32 | 6) ArcLength Documentation: https://docs.opencv.org/3.1.0/dd/d49/tutorial_py_contour_features.html 33 | 7) Perspective Transform Pyimage Search Tutorial https://www.pyimagesearch.com/2014/08/25/4-point-opencv-getperspective-transform-example/ 34 | -------------------------------------------------------------------------------- /Scanner.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import mapper 4 | image=cv2.imread("test_img.jpg") #read in the image 5 | image=cv2.resize(image,(1300,800)) #resizing because opencv does not work well with bigger images 6 | orig=image.copy() 7 | 8 | gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) #RGB To Gray Scale 9 | cv2.imshow("Title",gray) 10 | 11 | blurred=cv2.GaussianBlur(gray,(5,5),0) #(5,5) is the kernel size and 0 is sigma that determines the amount of blur 12 | cv2.imshow("Blur",blurred) 13 | 14 | edged=cv2.Canny(blurred,30,50) #30 MinThreshold and 50 is the MaxThreshold 15 | cv2.imshow("Canny",edged) 16 | 17 | 18 | contours,hierarchy=cv2.findContours(edged,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) #retrieve the contours as a list, with simple apprximation model 19 | contours=sorted(contours,key=cv2.contourArea,reverse=True) 20 | 21 | #the loop extracts the boundary contours of the page 22 | for c in contours: 23 | p=cv2.arcLength(c,True) 24 | approx=cv2.approxPolyDP(c,0.02*p,True) 25 | 26 | if len(approx)==4: 27 | target=approx 28 | break 29 | approx=mapper.mapp(target) #find endpoints of the sheet 30 | 31 | pts=np.float32([[0,0],[800,0],[800,800],[0,800]]) #map to 800*800 target window 32 | 33 | op=cv2.getPerspectiveTransform(approx,pts) #get the top or bird eye view effect 34 | dst=cv2.warpPerspective(orig,op,(800,800)) 35 | 36 | 37 | cv2.imshow("Scanned",dst) 38 | # press q or Esc to close 39 | cv2.waitKey(0) 40 | cv2.destroyAllWindows() 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /mapper.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def mapp(h): 4 | h = h.reshape((4,2)) 5 | hnew = np.zeros((4,2),dtype = np.float32) 6 | 7 | add = h.sum(1) 8 | hnew[0] = h[np.argmin(add)] 9 | hnew[2] = h[np.argmax(add)] 10 | 11 | diff = np.diff(h,axis = 1) 12 | hnew[1] = h[np.argmin(diff)] 13 | hnew[3] = h[np.argmax(diff)] 14 | 15 | return hnew 16 | -------------------------------------------------------------------------------- /test_img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdityaPai2398/CamScanner-In-Python/1dfad528594d570d6183113940c6b7decadc0890/test_img.jpg --------------------------------------------------------------------------------