C++ implementation of a ScienceDirect paper "An accelerating cpu-based correlation-based image alignment for real-time automatic optical inspection"
C++
1,162
154 commits
updated Jan 20, 2026
Using C++/MFC/OpenCV to build a Normalized Cross Corelation-based image alignment algorithm
The result means the similarity of two images, and the formular is as followed:


rotation invariant, and rotation precision is as high as possible
using image pyrimid as a searching strategy to speed up 4~128 times the original NCC method (depending on template size), minimizing the inspection area on the top level of image pyrimid
optimizing rotation time comsuming from OpenCV by setting needed "size" and modifying rotation matrix
SIMD version of image convolution (especially useful for large templates)
4.1 update Neon SIMD on MacOS version .so, super fast
optimizing the function GetNextMaxLoc () with struct s_BlockMax, for special cases whose template sizes are extremely smaller than source sizes, and for large TargetNumber.
It gets quite far.
Test case: Src10 (3648 X 3648) and Dst10 (54 X 54)
Effect: time consuming reduces from 534 ms to 100 ms. speed up 434%
![]() Inspection Image: 4024 X 3036 |
![]() Template Image: 762 X 521 |
| Library | Index | Score | Angle | PosX | PosY | Execution Time |
|---|---|---|---|---|---|---|
| My Tool | 0 | 1 | 0.046 | 1725.857 | 1045.433 | 76ms 🎖️ |
| My Tool | 1 | 0.998 | -119.979 | 2662.869 | 1537.446 | |
| My Tool | 2 | 0.991 | 120.150 | 1768.936 | 2098.494 | |
| Cognex | 0 | 1 | 0.030 | 1725.960 | 1045.470 | 125ms |
| Cognex | 1 | 0.989 | -119.960 | 2663.750 | 1538.040 | |
| Cognex | 2 | 0.983 | 120.090 | 1769.250 | 2099.410 | |
| Aisys | 0 | 1 | 0 | 1726.000 | 1045.500 | 202ms |
| Aisys | 1 | 0.990 | -119.935 | 2663.630 | 1539.060 | |
| Aisys | 2 | 0.979 | 120.000 | 1769.63 | 2099.780 |
note: if you want to get a best performance, please make sure you are using release verson (both this project and OpenCV dll). That's because O2-related settings significantly affects efficiency, and the difference of Debug and Release can up to 7 times for some cases.
test0 - with user interface

| Test | Metrics | Image |
|---|---|---|
| Test1 | Execution Time: 164ms (80ms with SIMD) Parameters: TargetNum=5 Overlap=0.8 Score=0.8 Tolerance Angle=180 | ![]() |
| Test2 | Execution Time: 237ms (175ms with SIMD) | ![]() |
| Test3 | Execution Time: 152ms (100ms with SIMD) | ![]() |
| Test4 | Execution Time: 21ms Parameters: TargetNum=38 Score=0.8 Tolerance Angle=0 Min Reduced Area=256 | ![]() |
| Test5 | Execution Time: 27ms | ![]() |
| Test6 | Execution Time: 1157ms (657ms with SIMD) Parameters: TargetNum=15 Score=0.8 Tolerance Angle=180 Min Reduced Area=256 | ![]() |
| Test7 | Execution Time: 18ms Parameters: TargetNum=100 Score=0.5 Tolerance Angle=0 MaxOverlap=0.5 Min Reduced Area=1024 | ![]() |
1.Select Debug_4.X or Release_4.X in "Solution Configuration"

2.Do step 10~12 in previous section


contact information: [email protected]

If you encounter an error(exception) on the constructor of opencv class "RotatedRect", modify the content in types.cpp:
this might due to Windows updates
RotatedRect::RotatedRect(const Point2f& _point1, const Point2f& _point2, const Point2f& _point3)
{
Point2f _center = 0.5f * (_point1 + _point3);
Vec2f vecs[2];
vecs[0] = Vec2f(_point1 - _point2);
vecs[1] = Vec2f(_point2 - _point3);
double x = std::max(norm(_point1), std::max(norm(_point2), norm(_point3)));
double a = std::min(norm(vecs[0]), norm(vecs[1]));
// check that given sides are perpendicular
// this is the line you need to modify
CV_Assert( std::fabs(vecs[0].ddot(vecs[1])) * a <= FLT_EPSILON * 9 * x * (norm(vecs[0]) * norm(vecs[1])) );
// wd_i stores which vector (0,1) or (1,2) will make the width
// One of them will definitely have slope within -1 to 1
int wd_i = 0;
if( std::fabs(vecs[1][1]) < std::fabs(vecs[1][0]) ) wd_i = 1;
int ht_i = (wd_i + 1) % 2;
float _angle = std::atan(vecs[wd_i][1] / vecs[wd_i][0]) * 180.0f / (float) CV_PI;
float _width = (float) norm(vecs[wd_i]);
float _height = (float) norm(vecs[ht_i]);
center = _center;
size = Size2f(_width, _height);
angle = _angle;
}
modify threshold value FLT_EPSILON of CV_Assert line to a bigger one
then recompile the source code
782 followers · starred Aug 2022
93 followers · starred Dec 2023
74 followers · starred Aug 2023
67 followers · starred Mar 2024
C++ implementation of a ScienceDirect paper "An accelerating cpu-based correlation-based image alignment for real-time automatic optical inspection"
C++
1,162
154 commits
updated Jan 20, 2026
Using C++/MFC/OpenCV to build a Normalized Cross Corelation-based image alignment algorithm
The result means the similarity of two images, and the formular is as followed:


rotation invariant, and rotation precision is as high as possible
using image pyrimid as a searching strategy to speed up 4~128 times the original NCC method (depending on template size), minimizing the inspection area on the top level of image pyrimid
optimizing rotation time comsuming from OpenCV by setting needed "size" and modifying rotation matrix
SIMD version of image convolution (especially useful for large templates)
4.1 update Neon SIMD on MacOS version .so, super fast
optimizing the function GetNextMaxLoc () with struct s_BlockMax, for special cases whose template sizes are extremely smaller than source sizes, and for large TargetNumber.
It gets quite far.
Test case: Src10 (3648 X 3648) and Dst10 (54 X 54)
Effect: time consuming reduces from 534 ms to 100 ms. speed up 434%
![]() Inspection Image: 4024 X 3036 |
![]() Template Image: 762 X 521 |
| Library | Index | Score | Angle | PosX | PosY | Execution Time |
|---|---|---|---|---|---|---|
| My Tool | 0 | 1 | 0.046 | 1725.857 | 1045.433 | 76ms 🎖️ |
| My Tool | 1 | 0.998 | -119.979 | 2662.869 | 1537.446 | |
| My Tool | 2 | 0.991 | 120.150 | 1768.936 | 2098.494 | |
| Cognex | 0 | 1 | 0.030 | 1725.960 | 1045.470 | 125ms |
| Cognex | 1 | 0.989 | -119.960 | 2663.750 | 1538.040 | |
| Cognex | 2 | 0.983 | 120.090 | 1769.250 | 2099.410 | |
| Aisys | 0 | 1 | 0 | 1726.000 | 1045.500 | 202ms |
| Aisys | 1 | 0.990 | -119.935 | 2663.630 | 1539.060 | |
| Aisys | 2 | 0.979 | 120.000 | 1769.63 | 2099.780 |
note: if you want to get a best performance, please make sure you are using release verson (both this project and OpenCV dll). That's because O2-related settings significantly affects efficiency, and the difference of Debug and Release can up to 7 times for some cases.
test0 - with user interface

| Test | Metrics | Image |
|---|---|---|
| Test1 | Execution Time: 164ms (80ms with SIMD) Parameters: TargetNum=5 Overlap=0.8 Score=0.8 Tolerance Angle=180 | ![]() |
| Test2 | Execution Time: 237ms (175ms with SIMD) | ![]() |
| Test3 | Execution Time: 152ms (100ms with SIMD) | ![]() |
| Test4 | Execution Time: 21ms Parameters: TargetNum=38 Score=0.8 Tolerance Angle=0 Min Reduced Area=256 | ![]() |
| Test5 | Execution Time: 27ms | ![]() |
| Test6 | Execution Time: 1157ms (657ms with SIMD) Parameters: TargetNum=15 Score=0.8 Tolerance Angle=180 Min Reduced Area=256 | ![]() |
| Test7 | Execution Time: 18ms Parameters: TargetNum=100 Score=0.5 Tolerance Angle=0 MaxOverlap=0.5 Min Reduced Area=1024 | ![]() |
1.Select Debug_4.X or Release_4.X in "Solution Configuration"

2.Do step 10~12 in previous section


contact information: [email protected]

If you encounter an error(exception) on the constructor of opencv class "RotatedRect", modify the content in types.cpp:
this might due to Windows updates
RotatedRect::RotatedRect(const Point2f& _point1, const Point2f& _point2, const Point2f& _point3)
{
Point2f _center = 0.5f * (_point1 + _point3);
Vec2f vecs[2];
vecs[0] = Vec2f(_point1 - _point2);
vecs[1] = Vec2f(_point2 - _point3);
double x = std::max(norm(_point1), std::max(norm(_point2), norm(_point3)));
double a = std::min(norm(vecs[0]), norm(vecs[1]));
// check that given sides are perpendicular
// this is the line you need to modify
CV_Assert( std::fabs(vecs[0].ddot(vecs[1])) * a <= FLT_EPSILON * 9 * x * (norm(vecs[0]) * norm(vecs[1])) );
// wd_i stores which vector (0,1) or (1,2) will make the width
// One of them will definitely have slope within -1 to 1
int wd_i = 0;
if( std::fabs(vecs[1][1]) < std::fabs(vecs[1][0]) ) wd_i = 1;
int ht_i = (wd_i + 1) % 2;
float _angle = std::atan(vecs[wd_i][1] / vecs[wd_i][0]) * 180.0f / (float) CV_PI;
float _width = (float) norm(vecs[wd_i]);
float _height = (float) norm(vecs[ht_i]);
center = _center;
size = Size2f(_width, _height);
angle = _angle;
}
modify threshold value FLT_EPSILON of CV_Assert line to a bigger one
then recompile the source code
782 followers · starred Aug 2022
93 followers · starred Dec 2023
74 followers · starred Aug 2023
67 followers · starred Mar 2024