比较旋转图像
Comparing rotated images
我正在寻找一种方法来比较几乎相同(相似度超过 95%)但可以绕中心轴旋转的图像。
我是整个计算机 graphics/vision 领域的新手,不确定是否有现成的构建工具或系统,或者即使这是正确的堆栈交换问题。
目前,我正在研究使用 C# 生成位图直方图,然后 运行 通过 Panda 对其进行分析,并根据直方图的相似性理想地对图像进行分组,尽管我听说过类似OpenCv + tesseract 可能是一个可行的选择。
您可以使用旋转和缩放不变算法使用特征点提取和匹配来比较图像相似度。
OpenCV 中已经提供了旋转不变特征匹配算法 - SIFT
,SURF 但这些都是专利的所以如果你想在商业上使用它们你必须付费。
幸运的是,SIFT 或 SURF 的有效替代方案可用,即 ORB(Oriented FAST and Rotated BRIEF)
除了少数文档图像之外,这些算法在大多数图像中都运行良好。
PS: 正如问题中提到的 (OpenCV + tesseract) 或者可以通过使用 Tesseract 库(开源 OCR 引擎)提取图像中的文本内容来用于文档图像
您需要计算两个图像之间的仿射变换矩阵,以便获得有关缩放、平移和旋转的信息。
这个矩阵看起来如何,如何获得旋转差异?
From this answer:
我使用了以下 Java 代码(使用 OpenCV 3.2)计算 缩放 ,translation 和 rotation 两个 Mat 图像之间的区别。我希望你会发现它有用。
static void calculateDifferences(Mat img1, Mat img2){
// Initialization
FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB);
DescriptorExtractor descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB);
DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
// First image objects
Mat img1_descriptors = new Mat();
MatOfKeyPoint img1_keypoints_mat = new MatOfKeyPoint();
// Detect KeyPoints for first image
detector.detect(img1, img1_keypoints_mat);
descriptor.compute(img1, img1_keypoints_mat, img1_descriptors);
// Second image objects
Mat img2_descriptors = new Mat();
MatOfKeyPoint img2_keypoints_mat = new MatOfKeyPoint();
// Detect KeyPoints for second image
detector.detect(img2, img2_keypoints_mat);
descriptor.compute(img2, img2_keypoints_mat, img2_descriptors);
// Match KeyPoints
MatOfDMatch matOfDMatch = new MatOfDMatch();
matcher.match(img1_descriptors, img2_descriptors, matOfDMatch);
// Filtering the matches
List<DMatch> dMatchList = matOfDMatch.toList();
Double max_dist = 0.0;
Double min_dist = 100.0;
for(int i = 0; i < img1_descriptors.rows(); i++){
Double dist = (double) dMatchList.get(i).distance;
if(dist < min_dist) min_dist = dist;
if(dist > max_dist) max_dist = dist;
}
LinkedList<DMatch> good_matches = new LinkedList<>();
for(int i = 0; i < img1_descriptors.rows(); i++){
if(dMatchList.get(i).distance < 3*min_dist){
good_matches.addLast(dMatchList.get(i));
}
}
// Converting to MatOfPoint2f format
LinkedList<Point> img1_points_list = new LinkedList<>();
LinkedList<Point> img2_points_list = new LinkedList<>();
List<KeyPoint> img1_keyPoints_list = img1_keypoints_mat.toList();
List<KeyPoint> img2_keyPoints_list = img2_keypoints_mat.toList();
int limit = good_matches.size();
for(int i = 0; i < limit; i++){
img1_points_list.addLast(img1_keyPoints_list.get(good_matches.get(i).queryIdx).pt);
img2_points_list.addLast(img2_keyPoints_list.get(good_matches.get(i).trainIdx).pt);
}
MatOfPoint2f img1_point2f_mat = new MatOfPoint2f();
img1_point2f_mat.fromList(img1_points_list);
MatOfPoint2f img2_point2f_mat = new MatOfPoint2f();
img2_point2f_mat.fromList(img2_points_list);
// Computing the affine transform matrix
Mat result = Video.estimateRigidTransform(img1_point2f_mat, img2_point2f_mat, true);
printMat(result); // Printing the optimal affine transformation 2x3 array
// The following variables correspond to the estimateRigidTransform result as shown here:
double a = result.get(0,0)[0];
double b = result.get(0,1)[0];
double d = result.get(1,1)[0];
double c = result.get(1,0)[0];
double tx = result.get(0,2)[0];
double ty = result.get(1,2)[0];
// Solving for scale,translation and rotation as shown in the link above
double scale_x = Math.signum(a) * Math.sqrt( (a*a) + (b*b) ); // Axis x scale difference
double scale_y = Math.signum(d) * Math.sqrt( (c*c) + (d*d) ); // Axis y scale difference
double translation = ty; // The translation difference
double rotation_angle = Math.atan2(c,d); // Rotation difference
// Printing results
println("Scale_x diff: " + scale_x);
println("Scale_y diff: " + scale_y);
println("Translation diff: " + translation);
println("Rotation diff: " + rotation_angle);
}
static void printMat(Mat m)
{
for (int x=0; x < m.height(); x++) {
for (int y=0; y < m.width(); y++) {
System.out.printf("%f",m.get(x,y)[0]);
System.out.printf("%s"," ");
}
System.out.println();
}
}
我正在寻找一种方法来比较几乎相同(相似度超过 95%)但可以绕中心轴旋转的图像。
我是整个计算机 graphics/vision 领域的新手,不确定是否有现成的构建工具或系统,或者即使这是正确的堆栈交换问题。
目前,我正在研究使用 C# 生成位图直方图,然后 运行 通过 Panda 对其进行分析,并根据直方图的相似性理想地对图像进行分组,尽管我听说过类似OpenCv + tesseract 可能是一个可行的选择。
您可以使用旋转和缩放不变算法使用特征点提取和匹配来比较图像相似度。
OpenCV 中已经提供了旋转不变特征匹配算法 - SIFT ,SURF 但这些都是专利的所以如果你想在商业上使用它们你必须付费。
幸运的是,SIFT 或 SURF 的有效替代方案可用,即 ORB(Oriented FAST and Rotated BRIEF)
除了少数文档图像之外,这些算法在大多数图像中都运行良好。
PS: 正如问题中提到的 (OpenCV + tesseract) 或者可以通过使用 Tesseract 库(开源 OCR 引擎)提取图像中的文本内容来用于文档图像
您需要计算两个图像之间的仿射变换矩阵,以便获得有关缩放、平移和旋转的信息。
这个矩阵看起来如何,如何获得旋转差异?
From this answer:
我使用了以下 Java 代码(使用 OpenCV 3.2)计算 缩放 ,translation 和 rotation 两个 Mat 图像之间的区别。我希望你会发现它有用。
static void calculateDifferences(Mat img1, Mat img2){
// Initialization
FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB);
DescriptorExtractor descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB);
DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
// First image objects
Mat img1_descriptors = new Mat();
MatOfKeyPoint img1_keypoints_mat = new MatOfKeyPoint();
// Detect KeyPoints for first image
detector.detect(img1, img1_keypoints_mat);
descriptor.compute(img1, img1_keypoints_mat, img1_descriptors);
// Second image objects
Mat img2_descriptors = new Mat();
MatOfKeyPoint img2_keypoints_mat = new MatOfKeyPoint();
// Detect KeyPoints for second image
detector.detect(img2, img2_keypoints_mat);
descriptor.compute(img2, img2_keypoints_mat, img2_descriptors);
// Match KeyPoints
MatOfDMatch matOfDMatch = new MatOfDMatch();
matcher.match(img1_descriptors, img2_descriptors, matOfDMatch);
// Filtering the matches
List<DMatch> dMatchList = matOfDMatch.toList();
Double max_dist = 0.0;
Double min_dist = 100.0;
for(int i = 0; i < img1_descriptors.rows(); i++){
Double dist = (double) dMatchList.get(i).distance;
if(dist < min_dist) min_dist = dist;
if(dist > max_dist) max_dist = dist;
}
LinkedList<DMatch> good_matches = new LinkedList<>();
for(int i = 0; i < img1_descriptors.rows(); i++){
if(dMatchList.get(i).distance < 3*min_dist){
good_matches.addLast(dMatchList.get(i));
}
}
// Converting to MatOfPoint2f format
LinkedList<Point> img1_points_list = new LinkedList<>();
LinkedList<Point> img2_points_list = new LinkedList<>();
List<KeyPoint> img1_keyPoints_list = img1_keypoints_mat.toList();
List<KeyPoint> img2_keyPoints_list = img2_keypoints_mat.toList();
int limit = good_matches.size();
for(int i = 0; i < limit; i++){
img1_points_list.addLast(img1_keyPoints_list.get(good_matches.get(i).queryIdx).pt);
img2_points_list.addLast(img2_keyPoints_list.get(good_matches.get(i).trainIdx).pt);
}
MatOfPoint2f img1_point2f_mat = new MatOfPoint2f();
img1_point2f_mat.fromList(img1_points_list);
MatOfPoint2f img2_point2f_mat = new MatOfPoint2f();
img2_point2f_mat.fromList(img2_points_list);
// Computing the affine transform matrix
Mat result = Video.estimateRigidTransform(img1_point2f_mat, img2_point2f_mat, true);
printMat(result); // Printing the optimal affine transformation 2x3 array
// The following variables correspond to the estimateRigidTransform result as shown here:
double a = result.get(0,0)[0];
double b = result.get(0,1)[0];
double d = result.get(1,1)[0];
double c = result.get(1,0)[0];
double tx = result.get(0,2)[0];
double ty = result.get(1,2)[0];
// Solving for scale,translation and rotation as shown in the link above
double scale_x = Math.signum(a) * Math.sqrt( (a*a) + (b*b) ); // Axis x scale difference
double scale_y = Math.signum(d) * Math.sqrt( (c*c) + (d*d) ); // Axis y scale difference
double translation = ty; // The translation difference
double rotation_angle = Math.atan2(c,d); // Rotation difference
// Printing results
println("Scale_x diff: " + scale_x);
println("Scale_y diff: " + scale_y);
println("Translation diff: " + translation);
println("Rotation diff: " + rotation_angle);
}
static void printMat(Mat m)
{
for (int x=0; x < m.height(); x++) {
for (int y=0; y < m.width(); y++) {
System.out.printf("%f",m.get(x,y)[0]);
System.out.printf("%s"," ");
}
System.out.println();
}
}