Document Normalizer in C++ - User Guide
In this guide, you will learn step by step on how to build a document normalization application with Dynamsoft Document Normalizer SDK using C++ language.
Read more on Dynamsoft Document Normalizer Features
- Document Normalizer in C++ - User Guide
Installation
If you haven’t downloaded the SDK yet, download the C++ Package
now and unpack the package into a directory of your choice.
For this tutorial, we unpack it to a pseudo directory
[INSTALLATION FOLDER]
, change it to your unpacking path for the following content.
To find out whether your environment is supported, read the System Requirements.
Build Your First Application
Let’s start by creating a console application which demonstrates how to use the minimum code to detect and normalize a document from an picture of it.
Create a New Project
- For Windows
-
Open Visual Studio. Go to “File > New > Project…” or click “Create a new project” on the starting page, choose “Console App”, create a new Empty Project and set the Project name as
NormalizeAnImage
. -
Add a new source file named
NormalizeAnImage.cpp
into the project.
- For Linux
- Create a new source file named
NormalizeAnImage.cpp
and place it into the folder[INSTALLATION FOLDER]/Dynamsoft/Resources/DocumentNormalizer/Samples/HelloWorld/NormalizeAnImage
.
Include the Library
-
Add headers and libs in
NormalizeAnImage.cpp
.#include <iostream> #include <string> #include "[INSTALLATION FOLDER]/Dynamsoft/Include/DynamsoftCaptureVisionRouter.h" using namespace std; using namespace dynamsoft::license; using namespace dynamsoft::cvr; using namespace dynamsoft::ddn; #if defined(_WIN64) || defined(_WIN32) #ifdef _WIN64 #pragma comment(lib, "[INSTALLATION FOLDER]/Dynamsoft/Distributables/Lib/Windows/x64/DynamsoftCaptureVisionRouterx64.lib") #pragma comment(lib, "[INSTALLATION FOLDER]/Dynamsoft/Distributables/Lib/Windows/x64/DynamsoftCorex64.lib") #pragma comment(lib, "[INSTALLATION FOLDER]/Dynamsoft/Distributables/Lib/Windows/x64/DynamsoftLicensex64.lib") #pragma comment(lib, "[INSTALLATION FOLDER]/Dynamsoft/Distributables/Lib/Windows/x64/DynamsoftUtilityx64.lib") #else #pragma comment(lib, "[INSTALLATION FOLDER]/Dynamsoft/Distributables/Lib/Windows/x86/DynamsoftCaptureVisionRouterx86.lib") #pragma comment(lib, "[INSTALLATION FOLDER]/Dynamsoft/Distributables/Lib/Windows/x86/DynamsoftCorex86.lib") #pragma comment(lib, "[INSTALLATION FOLDER]/Dynamsoft/Distributables/Lib/Windows/x86/DynamsoftLicensex86.lib") #pragma comment(lib, "[INSTALLATION FOLDER]/Dynamsoft/Distributables/Lib/Windows/x86/DynamsoftUtilityx86.lib") #endif #endif
Initialize a Capture Vision Router Instance
-
Initialize the license key.
int errorcode = 0; char errorMsg[256] = {0}; errorcode = CLicenseManager::InitLicense("DLS2eyJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSJ9", errorMsg, 256); if (errorcode != ErrorCode::EC_OK && errorcode != ErrorCode::EC_LICENSE_CACHE_USED) { cout << "License initialization failed: ErrorCode: " << errorcode << ", ErrorString: " << errorMsg << endl; } else { // other codes... }
The string “DLS2eyJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSJ9” here is a free public trial license. Note that network connection is required for this license to work. When it expires, you can request a 30-day trial license via the Request a Trial License link.
-
Create an instance of Capture Vision Router.
CCaptureVisionRouter *router = new CCaptureVisionRouter;
Detect and Save the Normalized Document
-
Apply normalization for an image file.
string imageFile = "../../../Images/sample-image.png"; CCapturedResult* result = router->Capture(imageFile.c_str(), CPresetTemplate::PT_DETECT_AND_NORMALIZE_DOCUMENT);
-
Save the normalized result as an image file.
cout << "File: " << imageFile << endl; /* * results is an Array of CCapturedResult objects, each object is the result of an image. */ if (result->GetErrorCode() != 0) { cout << "Error: " << result->GetErrorCode() << "," << result->GetErrorString() << endl; } /* * There can be multiple types of result items per image. * We check each of these items until we find the normalized image. */ int count = result->GetItemsCount(); cout << "Normalized " << count << " documents" << endl; for (int i = 0; i < count; i++) { const CCapturedResultItem* item = result->GetItem(i); CapturedResultItemType type = item->GetType(); if (type == CapturedResultItemType::CRIT_NORMALIZED_IMAGE) { const CNormalizedImageResultItem* normalizedImage = dynamic_cast<const CNormalizedImageResultItem*>(item); string outPath = "normalizedResult_"; outPath += to_string(i) + ".png"; CImageManager manager; // Save normalized image to file. errorcode = manager.SaveToFile(normalizedImage->GetImageData(), outPath.c_str()); if (errorcode == 0) { cout << "Document " << i << " file: " << outPath << endl; } } }
-
Release the allocated memory.
result->Release(); delete router, router = NULL;
Build and Run the Project
- For Windows
-
In Visual Studio, set the solution to build as Release|x64.
-
Build the project to generate program
NormalizeAnImage.exe
. -
Copy ALL
*.dll
files under[INSTALLATION FOLDER]/Dynamsoft/Lib/Windows/x64
to the same folder as theNormalizeAnImage.exe
-
Copy
[INSTALLATION FOLDER]/Dynamsoft/Distributables/DDN-PresetTemplates.json
to the same folder as theNormalizeAnImage.exe
. -
Run the program
NormalizeAnImage.exe
.
The SDK supports both x86 and x64, please set the platform based on your needs.
- For Linux
-
Open a terminal and change to the target directory where
NormalizeAnImage.cpp
is located. Build the sample:g++ -o NormalizeAnImage NormalizeAnImage.cpp -lDynamsoftCore -lDynamsoftLicense -lDynamsoftUtility -lDynamsoftCaptureVisionRouter -L ../../../Lib/Linux/x64 -Wl,-rpath=../../../Lib/Linux/x64 -std=c++11 cp ../Distributables/DDN-PresetTemplates.json ../Distributables/Lib/Linux/x64
-
Run the program
NormalizeAnImage
../NormalizeAnImage
Process Multiple Images
If you need to process multiple images at once instead of one image, you can follow these steps:
Preparation Steps
- Create a new project named
NormalizeMultipleImages
. - Initialize a Capture Vision Router Instance.
- Include the Library.
You can download the complete source code from here.
Add an Image Source as the Input
The class CDirectoryFetcher
is capable of converting a local directory to an image source. We will use it to connect multiple images to the image-processing engine.
-
Setting up a directory fetcher to retrieve image data sources from a directory.
CDirectoryFetcher *dirFetcher = new CDirectoryFetcher; dirFetcher->SetDirectory("[Your Image Path]"); router->SetInput(dirFetcher);
-
Create a class
MyImageSourceStateListener
to implement theCImageSourceStateListenter
interface, and callStopCapturing
in the callback function.class MyImageSourceStateListener : public CImageSourceStateListener { private: CCaptureVisionRouter* m_router; public: MyImageSourceStateListener(CCaptureVisionRouter* router) { m_router = router; } virtual void OnImageSourceStateReceived(ImageSourceState state) { if (state == ISS_EXHAUSTED) m_router->StopCapturing(); } };
-
Register the
MyImageSourceStateListener
object to monitor the status of the image source.CImageSourceStateListener *listener = new MyImageSourceStateListener(router); router->AddImageSourceStateListener(listener);
Add a Result Receiver as the Output
-
Define the receiver class.
class MyResultReceiver : public CCapturedResultReceiver { void OnNormalizedImagesReceived(CNormalizedImagesResult* pResult) { const CFileImageTag *tag = dynamic_cast<const CFileImageTag*>(pResult->GetOriginalImageTag()); cout << "File: " << tag->GetFilePath() << endl; if (pResult->GetErrorCode() != EC_OK) { cout << "Error: " << pResult->GetErrorString() << endl; } else { CImageManager manager; int lCount = pResult->GetItemsCount(); cout << "Normalized " << lCount << " documents" << endl; for (int li = 0; li < lCount; ++li) { const CNormalizedImageResultItem* item = pResult->GetItem(li); string outPath = "normalizeImage_"; outPath += to_string(li) + ".png"; manager.SaveToFile(item->GetImageData(), outPath.c_str()); cout << "Document " << li << " file: " << outPath << endl; } } cout << endl; } };
For the error handling mechanism, the SDK returns Error Code in the
CNormalizedImagesResult
object. You can add error handling code as needed. See Error Code for a full list of supported error codes. -
Create a receiver object and set it as the output.
CCapturedResultReceiver *recv = new MyResultReceiver; router->AddResultReceiver(recv);
Start the Process
-
Call the method
StartCapturing()
to start processing all the images in the specified folder.router->StartCapturing(CPresetTemplate::PT_DETECT_AND_NORMALIZE_DOCUMENT, true);
During the process, the callback function
OnNormalizedImagesReceived()
is triggered each time an image finishes processing. After all images are processed, the listener functionOnImageSourceStateReceived()
will return the image source state asISS_EXHAUSTED
and the process is stopped with the methodStopCapturing()
.
Release Allocated Memory
delete router, router = NULL;
delete dirFetcher, dirFetcher = NULL;
delete listener, listener = NULL;
delete recv, recv = NULL;
Build and Run the Project Again
Please refer to Build and Run the Project.