{"id":15998208,"url":"https://github.com/yushulx/python-document-scanner-sdk","last_synced_at":"2025-06-12T16:09:55.941Z","repository":{"id":58700015,"uuid":"531813837","full_name":"yushulx/python-document-scanner-sdk","owner":"yushulx","description":"Python document detection SDK built with Dynamsoft Document Normalizer for Windows and Linux","archived":false,"fork":false,"pushed_at":"2024-10-17T05:42:37.000Z","size":33521,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-29T16:19:33.717Z","etag":null,"topics":["document","document-detection","document-rectification","edge-detection","python"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/document-scanner-sdk/","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yushulx.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-02T06:49:12.000Z","updated_at":"2025-04-09T12:24:47.000Z","dependencies_parsed_at":"2024-08-19T04:26:46.361Z","dependency_job_id":"88f51f9c-b7d0-4bf7-b9ac-904730c36903","html_url":"https://github.com/yushulx/python-document-scanner-sdk","commit_stats":{"total_commits":20,"total_committers":1,"mean_commits":20.0,"dds":0.0,"last_synced_commit":"e5723d09c5eb4d8b7079740f46a9ca2492589698"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yushulx%2Fpython-document-scanner-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yushulx%2Fpython-document-scanner-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yushulx%2Fpython-document-scanner-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yushulx%2Fpython-document-scanner-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yushulx","download_url":"https://codeload.github.com/yushulx/python-document-scanner-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yushulx%2Fpython-document-scanner-sdk/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":257396316,"owners_count":22540254,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["document","document-detection","document-rectification","edge-detection","python"],"created_at":"2024-10-08T08:08:04.588Z","updated_at":"2025-06-12T16:09:55.916Z","avatar_url":"https://github.com/yushulx.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Python Document Scanner SDK \nThis project provides Python bindings for the [Dynamsoft C/C++ Document Scanner SDK v1.x](https://www.dynamsoft.com/document-normalizer/docs/core/introduction/?ver=latest\u0026ver=latest), enabling developers to quickly create document scanner applications for Windows and Linux desktop environments.\n\n\u003e Note: This project is an unofficial, community-maintained Python wrapper for the Dynamsoft Document Normalizer SDK. For those seeking the most reliable and fully-supported solution, Dynamsoft offers an official Python package. Visit the [Dynamsoft Capture Vision Bundle](https://pypi.org/project/dynamsoft-capture-vision-bundle/) page on PyPI for more details.\n\n## About Dynamsoft Capture Vision Bundle\n- Activate the SDK with a [30-day FREE trial license](https://www.dynamsoft.com/customer/license/trialLicense/?product=dcv\u0026package=cross-platform).\n- Install the SDK via `pip install dynamsoft-capture-vision-bundle`.\n\n### Comparison Table\n| Feature | Unofficial Wrapper (Community) | Official Dynamsoft Capture Vision SDK |\n| --- | --- | --- |\n| Support | Community-driven, best effort | Official support from Dynamsoft |\n| Documentation | README only | [Comprehensive Online Documentation](https://www.dynamsoft.com/capture-vision/docs/server/programming/python/?lang=python) |\n| API Coverage | Limited | Full API coverage |\n|Feature Updates| May lag behind the official SDK | First to receive new features |\n| Compatibility | Limited testing across environments| Thoroughly tested across all supported environments|\n| OS Support | Windows, Linux | Windows, Linux, **macOS** |\n\n## Supported Python Versions\n* Python 3.x\n\n## Dependencies\nInstall the required dependencies using pip:\n\n```bash \npip install opencv-python\n```\n\n## Command-line Usage\n- Scan documents from images:\n    \n    ```bash\n    scandocument -f \u003cfile-name\u003e -l \u003clicense-key\u003e\n    ```\n\n- Scan documents from a camera video stream:\n    \n    ```bash\n    scandocument -c 1 -l \u003clicense-key\u003e\n    ```\n\n## Quick Start\n- Scan documents from an image file:\n    ```python\n    import argparse\n    import docscanner\n    import sys\n    import numpy as np\n    import cv2\n    import time\n\n    def showNormalizedImage(name, normalized_image):\n        mat = docscanner.convertNormalizedImage2Mat(normalized_image)\n        cv2.imshow(name, mat)\n        return mat\n\n    def process_file(filename, scanner):\n        image = cv2.imread(filename)\n        results = scanner.detectMat(image)\n        for result in results:\n            x1 = result.x1\n            y1 = result.y1\n            x2 = result.x2\n            y2 = result.y2\n            x3 = result.x3\n            y3 = result.y3\n            x4 = result.x4\n            y4 = result.y4\n            \n            normalized_image = scanner.normalizeBuffer(image, x1, y1, x2, y2, x3, y3, x4, y4)\n            showNormalizedImage(\"Normalized Image\", normalized_image)\n            cv2.drawContours(image, [np.intp([(x1, y1), (x2, y2), (x3, y3), (x4, y4)])], 0, (0, 255, 0), 2)\n        \n        cv2.imshow('Document Image', image)\n        cv2.waitKey(0)\n        \n        normalized_image.save(str(time.time()) + '.png')\n        print('Image saved')\n\n    def scandocument():\n        \"\"\"\n        Command-line script for scanning documents from a given image\n        \"\"\"\n        parser = argparse.ArgumentParser(description='Scan documents from an image file')\n        parser.add_argument('-f', '--file', help='Path to the image file')\n        parser.add_argument('-l', '--license', default='', type=str, help='Set a valid license key')\n        args = parser.parse_args()\n        # print(args)\n        try:\n            filename = args.file\n            license = args.license\n            \n            if filename is None:\n                parser.print_help()\n                return\n            \n            # set license\n            if  license == '':\n                docscanner.initLicense(\"LICENSE-KEY\")\n            else:\n                docscanner.initLicense(license)\n                \n            # initialize mrz scanner\n            scanner = docscanner.createInstance()\n            ret = scanner.setParameters(docscanner.Templates.color)\n\n            if filename is not None:\n                process_file(filename, scanner)\n                \n        except Exception as err:\n            print(err)\n            sys.exit(1)\n\n    scandocument()\n    ```\n\n    ![python document scanner from file](https://www.dynamsoft.com/codepool/img/2022/09/document-perspective-correction.png)\n\n- Scan documents from camera video stream:\n    ```python\n    import argparse\n    import docscanner\n    import sys\n    import numpy as np\n    import cv2\n    import time\n\n    g_results = None\n    g_normalized_images = []\n\n\n    def callback(results):\n        global g_results\n        g_results = results\n\n\n    def showNormalizedImage(name, normalized_image):\n        mat = docscanner.convertNormalizedImage2Mat(normalized_image)\n        cv2.imshow(name, mat)\n        return mat\n\n\n    def process_video(scanner):\n        scanner.addAsyncListener(callback)\n\n        cap = cv2.VideoCapture(0)\n        while True:\n            ret, image = cap.read()\n\n            ch = cv2.waitKey(1)\n            if ch == 27:\n                break\n            elif ch == ord('n'):  # normalize image\n                if g_results != None:\n                    g_normalized_images = []\n                    index = 0\n                    for result in g_results:\n                        x1 = result.x1\n                        y1 = result.y1\n                        x2 = result.x2\n                        y2 = result.y2\n                        x3 = result.x3\n                        y3 = result.y3\n                        x4 = result.x4\n                        y4 = result.y4\n\n                        normalized_image = scanner.normalizeBuffer(\n                            image, x1, y1, x2, y2, x3, y3, x4, y4)\n                        g_normalized_images.append(\n                            (str(index), normalized_image))\n                        mat = showNormalizedImage(str(index), normalized_image)\n                        index += 1\n            elif ch == ord('s'):  # save image\n                for data in g_normalized_images:\n                    # cv2.imwrite('images/' + str(time.time()) + '.png', image)\n                    cv2.destroyWindow(data[0])\n                    data[1].save(str(time.time()) + '.png')\n                    print('Image saved')\n\n                g_normalized_images = []\n\n            if image is not None:\n                scanner.detectMatAsync(image)\n\n            if g_results != None:\n                for result in g_results:\n                    x1 = result.x1\n                    y1 = result.y1\n                    x2 = result.x2\n                    y2 = result.y2\n                    x3 = result.x3\n                    y3 = result.y3\n                    x4 = result.x4\n                    y4 = result.y4\n\n                    cv2.drawContours(\n                        image, [np.intp([(x1, y1), (x2, y2), (x3, y3), (x4, y4)])], 0, (0, 255, 0), 2)\n\n            cv2.putText(image, 'Press \"n\" to normalize image',\n                        (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)\n            cv2.putText(image, 'Press \"s\" to save image', (10, 60),\n                        cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)\n            cv2.putText(image, 'Press \"ESC\" to exit', (10, 90),\n                        cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)\n            cv2.imshow('Document Scanner', image)\n\n\n    docscanner.initLicense(\n        \"LICENSE-KEY\")\n\n    scanner = docscanner.createInstance()\n    ret = scanner.setParameters(docscanner.Templates.color)\n    process_video(scanner)\n\n    ```\n    \n    ![python document scanner from camera](https://www.dynamsoft.com/codepool/img/2022/09/python-document-scanner.png)\n\n## API Methods\n- `docscanner.initLicense('YOUR-LICENSE-KEY')`: Set the license key.\n    \n    ```python\n    docscanner.initLicense(\"LICENSE-KEY\")\n    ```\n\n- `docscanner.createInstance()`: Create a Document Scanner instance.\n    \n    ```python\n    scanner = docscanner.createInstance()\n    ```\n- `detectFile(filename)`: Perform edge detection from an image file.\n\n    ```python\n    results = scanner.detectFile(\u003cfilename\u003e)\n    ```\n- `detectMat(Mat image)`: Perform edge detection from an OpenCV Mat.\n    ```python\n    image = cv2.imread(\u003cfilename\u003e)\n    results = scanner.detectMat(image)\n    for result in results:\n        x1 = result.x1\n        y1 = result.y1\n        x2 = result.x2\n        y2 = result.y2\n        x3 = result.x3\n        y3 = result.y3\n        x4 = result.x4\n        y4 = result.y4\n    ```\n\n- `setParameters(Template)`: Select color, binary, or grayscale template.\n    \n    ```python\n    scanner.setParameters(docscanner.Templates.color)\n    ```\n\n- `addAsyncListener(callback function)`: Start a native thread to run document scanning tasks asynchronously.\n- `detectMatAsync(\u003copencv mat data\u003e)`: Queue a document scanning task into the native thread.\n    ```python\n    def callback(results):\n        for result in results:\n            print(result.x1)\n            print(result.y1)\n            print(result.x2)\n            print(result.y2)\n            print(result.x3)\n            print(result.y3)\n            print(result.x4)\n            print(result.y4)\n                                                        \n    import cv2\n    image = cv2.imread(\u003cfilename\u003e)\n    scanner.addAsyncListener(callback)\n    scanner.detectMatAsync(image)\n    sleep(5)\n    ```\n\n- `normalizeBuffer(mat, x1, y1, x2, y2, x3, y3, x4, y4)`: Perform perspective correction from an OpenCV Mat.\n    \n    ```python\n    normalized_image = scanner.normalizeBuffer(image, x1, y1, x2, y2, x3, y3, x4, y4)\n    ```\n- `normalizeFile(filename, x1, y1, x2, y2, x3, y3, x4, y4)`: Perform perspective correction from an image file.\n    \n    ```python\n    normalized_image = scanner.normalizeFile(\u003cfilename\u003e, x1, y1, x2, y2, x3, y3, x4, y4)\n    ```\n- `normalized_image.save(filename)`: Save the normalized image to a file.\n    ```python\n    normalized_image.save(\u003cfilename\u003e)\n    ```\n- `normalized_image.recycle()`: Release the memory of the normalized image.\n- `clearAsyncListener()`: Stop the native thread and clear the registered Python function.\n\n\n## How to Build the Python Document Scanner Extension\n- Create a source distribution:\n    \n    ```bash\n    python setup.py sdist\n    ```\n\n- setuptools:\n    \n    ```bash\n    python setup_setuptools.py build\n    python setup_setuptools.py develop \n    ```\n\n- Build wheel:\n    \n    ```bash\n    pip wheel . --verbose\n    # Or\n    python setup.py bdist_wheel\n    ```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyushulx%2Fpython-document-scanner-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyushulx%2Fpython-document-scanner-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyushulx%2Fpython-document-scanner-sdk/lists"}