C#调用C++ OpenCV4.4.0+VS2019

  • 基于OpenCV4.4.0的直方图匹配
    • 直方图比较
      • 相关系数的标准
      • 卡方系数的标准
      • 相交系数的标准
      • 巴氏系数的标准
      • 步骤
    • 直方图匹配原理
      • 直方图匹配优缺点
      • C++代码
    • C++代码转化为C#
      • 将C++代码编译成一个dll文件
      • C#调用dll文件

基于OpenCV4.4.0的直方图匹配

直方图比较

直方图比较,是用一定的标准来判断两个直方图的相似度方法;
OpenCV中提供的API是:
对输入的两张图像计算得到直方图H1与H2,归一化到相同的尺度空间然后可以通过计算H1与H2的之间的距离得到两个直方图的相似程度进而比较图像本身的相似程度。
Opencv提供的比较方法有四种:
1.Correlation 相关性比较
2.Chi - Square 卡方比较
3.Intersection 十字交叉性
4.Bhattacharyya distance 巴氏距离

相关系数的标准

相关系数的标准(method=CV_COMP_CORREL) 值越大,相关度越高,最大值为1,最小值为0

卡方系数的标准

卡方系数的标准(method=CV_COMP_CHISQR) 值越小,相关度越高,最大值无上界,最小值0

相交系数的标准

相交系数的标准(method=CV_COMP_INTERSECT)值越大,相关度越高,最大值为9.455319,最小值为0

巴氏系数的标准

巴氏系数的标准(method=CV_COMP_BHATTACHARYYA) 值越小,相关度越高,最大值为1,最小值为0

步骤

步骤:首先把图像从RGB色彩空间转换到HSV色彩空间cvtColor
计算图像的直方图,然后归一化到[0~1]之间calcHist和normalize;
使用上述四种比较方法之一进行比较compareHist

直方图匹配原理

任何一种颜色都是由红绿蓝三原色(RGB)构成的,所以上图共有4张直方图(三原色直方图 + 最后合成的直方图)。
如果每种原色都可以取256个值,那么整个颜色空间共有1600万种颜色(256的三次方)。针对这1600万种颜色比较直方图,计算量实在太大了,因此需要采用简化方法。可以将0~255分成四个区:0~63为第0区,64~127为第1区,128~191为第2区,192~255为第3区。这意味着红绿蓝分别有4个区,总共可以构成64种组合(4的3次方)。
任何一种颜色必然属于这64种组合中的一种,这样就可以统计每一种组合包含的像素数量。

上图是某张图片的颜色分布表,将表中最后一栏提取出来,组成一个64维向量(7414, 230, 0, 0, 8, …, 109, 0, 0, 3415, 53929)。这个向量就是这张图片的特征值或者叫"指纹"。

于是,寻找相似图片就变成了找出与其最相似的向量。

直方图匹配优缺点

优点:根据像素进行匹配,对于分辨率不同的图片效果较好,实验数据如下。
缺点:对于不同图片,但是相似,或是些许形变的图片,匹配效果并不好。

C++代码

//直方图比较
#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
#include<opencv2/highgui/highgui_c.h>
using namespace cv;
using namespace std;string convertToString(double d);
int main(int argc, char* argv)
{Mat base, test1, test2;Mat hsvbase, hsvtest1, hsvtest2;base = imread("C:/Users/wenhaofu/Desktop/picture/NBA1.png");test1 = imread("C:/Users/wenhaofu/Desktop/picture/NBA2.png");test2 = imread("C:/Users/wenhaofu/Desktop/picture/NBA3.png");if (!base.data){printf("could not load image...\n");return -1;}//步骤一:从RGB空间转换到HSV空间cvtColor(base, hsvbase, CV_BGR2HSV);cvtColor(test1, hsvtest1, CV_BGR2HSV);cvtColor(test2, hsvtest2, CV_BGR2HSV);//步骤二:计算直方图与归一化int h_bins = 50;int s_bins = 60;int histsize[] = { h_bins,s_bins };//hue varies from 0 to 179,saturation from 0 to 255float h_ranges[] = { 0,180 };float s_ranges[] = { 0,256 };const float* histRanges[] = { h_ranges,s_ranges };//use the 0-th and 1-st channelsint channels[] = { 0,1 };MatND hist_base;MatND hist_test1;MatND hist_test2;//计算直方图calcHist(&hsvbase, 1, channels, Mat(), hist_base, 2, histsize, histRanges, true, false);calcHist(&hsvtest1, 1, channels, Mat(), hist_test1, 2, histsize, histRanges, true, false);calcHist(&hsvtest2, 1, channels, Mat(), hist_test2, 2, histsize, histRanges, true, false);//归一化normalize(hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat());//归一化normalize(hist_test1, hist_test1, 0, 1, NORM_MINMAX, -1, Mat());normalize(hist_test2, hist_test2, 0, 1, NORM_MINMAX, -1, Mat());//步骤三:比较直方图,并返回值double basebase = compareHist(hist_base, hist_base, CV_COMP_BHATTACHARYYA);//比较直方图double basetest1 = compareHist(hist_base, hist_test1, CV_COMP_BHATTACHARYYA);double basetest2 = compareHist(hist_base, hist_test2, CV_COMP_BHATTACHARYYA);double test1test2 = compareHist(hist_test1, hist_test2, CV_COMP_BHATTACHARYYA);printf("test1 with test2 correlation value :%f", test1test2);//在原图中显示相关性参数putText(base, convertToString(basebase), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, CV_AA);putText(test1, convertToString(basetest1), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, CV_AA);putText(test2, convertToString(basetest2), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, CV_AA);putText(test2, convertToString(test1test2), Point(100, 100), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, CV_AA);namedWindow("base", CV_WINDOW_AUTOSIZE);namedWindow("test1", CV_WINDOW_AUTOSIZE);namedWindow("test2", CV_WINDOW_AUTOSIZE);imshow("base", base);imshow("test1", test1);imshow("test2", test2);waitKey(0);return 0;
}//由于comparehist计算出来的相关性的值是一个double型,这个函数就是把double转变为string
string convertToString(double d)
{ostringstream os;if (os << d)return os.str();return "invalid conversion";
}

C++代码转化为C#

将C++代码编译成一个dll文件

(1)在之前的C++代码上,在解决方案资源管理器中新建一个头文件(.h)

(2)在新建的头文件中,输入以下内容:

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
#include <opencv2/highgui/highgui_c.h>
#include <string>
using namespace std;
extern "C" __declspec(dllexport) std::string convertToString(double d);
extern "C" __declspec(dllexport) void histogram(char* s1, char* s2, char* s3);//因为c#与c++之间,string不能直接转换

extern "C"外部声明,表示函数和变量是按照C语言的方式编译和链接的。

_decspec(dllexport)的目的是为了将对应的函数放入到DLL动态库中。

extern “C” _declspec(dllexport)的目的是为了使用DllImport调用非托管C++的DLL文件。因为使用DllImport只能调用由C语言函数做的DLL。

c#与c++对应:

将string转为IntPtr:IntPtr
System.Runtime.InteropServices.Marshal.StringToCoTaskMemAuto(string)
将IntPtr转为string:string
System.Runtime.InteropServices.MarshalPtrToStringAuto(IntPtr) c++
<----------> c# BSTR --------- StringBuilder LPCTSTR ---------
StringBuilder LPCWSTR --------- IntPtr handle---------IntPtr
hwnd-----------IntPtr char *----------string int * -----------ref int
int &-----------ref int void *----------IntPtr unsigned char *-----ref
byte Struct需要在C#里重新定义一个Struct CallBack回调函数需要封装在一个委托里,delegate static
extern int FunCallBack(string str); 注意在每个函数的前面加上public static extern
+返回的数据类型,如果不加public ,函数默认为私有函数,调用就会出错。

(3)在之前的C++文件中,直接修改代码
至于C++如何配置环境;如何写;具体的怎么做可以看VS2019+OpenCV4.4.0安装及整合详细步骤

//直方图比较#include "Histogram.h"
using namespace cv;
using namespace std;//由于comparehist计算出来的相关性的值是一个double型,这个函数就是把double转变为string
std::string convertToString(double d)
{ostringstream os;if (os << d)return os.str();return "invalid conversion";
}
void histogram(char *s1, char *s2, char *s3) {Mat base, test1, test2;Mat hsvbase, hsvtest1, hsvtest2;base = imread(s1,1);test1 = imread(s2,1);test2 = imread(s3,1);if (!base.data || !test1.data || !test2.data){printf("could not load image...\n");return;}//步骤一:从RGB空间转换到HSV空间cvtColor(base, hsvbase, CV_BGR2HSV);cvtColor(test1, hsvtest1, CV_BGR2HSV);cvtColor(test2, hsvtest2, CV_BGR2HSV);//步骤二:计算直方图与归一化int h_bins = 50;int s_bins = 60;int histsize[] = { h_bins,s_bins };//hue varies from 0 to 179,saturation from 0 to 255float h_ranges[] = { 0,180 };float s_ranges[] = { 0,256 };const float* histRanges[] = { h_ranges,s_ranges };//use the 0-th and 1-st channelsint channels[] = { 0,1 };MatND hist_base;MatND hist_test1;MatND hist_test2;//计算直方图calcHist(&hsvbase, 1, channels, Mat(), hist_base, 2, histsize, histRanges, true, false);calcHist(&hsvtest1, 1, channels, Mat(), hist_test1, 2, histsize, histRanges, true, false);calcHist(&hsvtest2, 1, channels, Mat(), hist_test2, 2, histsize, histRanges, true, false);//归一化normalize(hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat());//归一化normalize(hist_test1, hist_test1, 0, 1, NORM_MINMAX, -1, Mat());normalize(hist_test2, hist_test2, 0, 1, NORM_MINMAX, -1, Mat());//步骤三:比较直方图,并返回值double basebase = compareHist(hist_base, hist_base, CV_COMP_CORREL);//比较直方图double basetest1 = compareHist(hist_base, hist_test1, CV_COMP_CORREL);double basetest2 = compareHist(hist_base, hist_test2, CV_COMP_CORREL);double test1test2 = compareHist(hist_test1, hist_test2, CV_COMP_CORREL);printf("test1 with test1 correlation value :%f", basebase);cout << endl;printf("test1 with test2 correlation value :%f", basetest1);cout << endl;printf("test1 with test3 correlation value :%f", basetest2);cout << endl;printf("test2 with test3 correlation value :%f", test1test2);//在原图中显示相关性参数putText(base, convertToString(basebase), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, CV_AA);putText(test1, convertToString(basetest1), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, CV_AA);putText(test2, convertToString(basetest2), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, CV_AA);putText(test2, convertToString(test1test2), Point(100, 100), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, CV_AA);namedWindow("base", CV_WINDOW_AUTOSIZE);namedWindow("test1", CV_WINDOW_AUTOSIZE);namedWindow("test2", CV_WINDOW_AUTOSIZE);imshow("base", base);imshow("test1", test1);imshow("test2", test2);waitKey(0);
}

(4)在源文件文件夹下新建模块定义文件(.def),输入以下内容:

LIBRARY Histogram
EXPORTS histogram
EXPORTS convertToString

EXPORTS后面的就是你要调用的方法名,生成.dll文件的同时也会生成.lib库。
(5)生成解决方案,这里可能生成没问题,但是最后运行C#会报错:

System.DllNotFoundException: Unable to load DLL 'XX.dll': 找不到指定的模块。 (Exception from HRESULT:

直接在这里解决了
这是运行库设置的问题,几个工程的运行库设置不一样。解决方法:
打开所引用的dll源码的项目属性页面,配置属性 -> C/C++ -> 代码生成 -> 运行库,将该项设置为 多线程调试 (/MTd),然后再重新生成解决方案,使用新的dll即可解决问题。

(6)再重新生成整个解决方案,可能又会出现以下错误:

这是因为输出文件拓展名的问题,解决方法如下:
【项目属性】→ 【配置属性】→【常规】→【目标文件扩展名】,将.exe,改为.dll
再重新生成解决方案

C#调用C++OpenCV直方图匹配相关推荐

  1. opencv 使用直方图匹配数字

    也是刚学opencv,参考一些资料,完成简单的数字匹配: #pragma once #include <iostream> #include <opencv2/core/utils/ ...

  2. OpenCV学习(二十) :直方图匹配、对比:calcHist(),minMaxLoc(),compareHist()

    直方图匹配.对比:calcHist ,minMaxLoc,compareHist 1.calcHist()函数 2.归一化:normalize()函数 3.minMaxLoc()函数 4.compar ...

  3. OpenCV基础(17)基于OpenCV、scikit-image和Python的直方图匹配

    在本教程中,您将学习如何使用OpenCV和scikit-image进行直方图匹配. 上周我们讨论了直方图均衡化,这是一种基本的图像处理技术,可以提高输入图像的对比度. 但是,如果你想自动匹配两幅图像的 ...

  4. 在OpenCV下写的直方图匹配(直方图规定化)C++源码!

    直方图匹配的原理就不多作解释了,我曾经还将MATLAB源码改写成过C源码,详情可见我的博文 根据MATLAB的histeq函数改写的运行在OpenCV下的直方图规定化C源码! 本文已转移到 https ...

  5. 【OpenCV】直方图应用:直方图均衡化,直方图匹配,对比直方图

    本文链接:https://blog.csdn.net/xiaowei_cqu/article/details/7606607                                       ...

  6. 【OpenCV 例程200篇】48. 图像增强—彩色直方图匹配

    [OpenCV 例程200篇]48. 图像增强-彩色直方图匹配 欢迎关注 『OpenCV 例程200篇』 系列,持续更新中 欢迎关注 『Python小白的OpenCV学习课』 系列,持续更新中 图像直 ...

  7. 【OpenCV 例程200篇】47. 图像增强—直方图匹配

    [OpenCV 例程200篇]47. 图像增强-直方图匹配 欢迎关注 『OpenCV 例程200篇』 系列,持续更新中 欢迎关注 『Python小白的OpenCV学习课』 系列,持续更新中 图像直方图 ...

  8. c++ opencv 图像处理:直方图处理(直方图均衡化,直方图匹配(规定化))

    文章目录 前言 一.直方图(histogram) 二.直方图处理 1.直方图均衡化 2.直方图匹配(规定化) 三.opencv函数总结 1.equalizeHist图像均衡化 2.calcHist获取 ...

  9. C++版本OpenCv教程(二十四)直方图匹配

    直方图均衡化函数可以自动的改变图像直方图的分布形式,这种方式极大的简化了直方图均衡化过程中需要的操作步骤,但是该函数不能指定均衡化后的直方图分布形式.在某些特定的条件下需要将直方图映射成指定的分布形式 ...

最新文章

  1. Vert.x学习笔记(一) Vert.x 核心包
  2. python的turtle怎么设置rgb颜色_Python : turtle色彩控制实例详解
  3. 网易云信全面技术支持,让“子弹短信”飞得更快
  4. 怎么说呢。留个纪念,关于字符串的重载
  5. 编译MiniGUI 程序
  6. 你真的理解事件绑定、事件冒泡和事件委托吗?
  7. 【渝粤题库】国家开放大学2021春2757宠物饲养题目
  8. 如何在centos中找到安装mysql_centos上如何安装mysql
  9. DNS解析原理与Bind部署DNS服务
  10. java hbase流量日志,Spark+Hbase 亿级流量分析实战(日志存储设计)
  11. Windows中安装 Redis 解压版
  12. 中科大计算机考研录取分数线_中科大计算机考研 | 跨考CS上岸经验分享!
  13. 20170724 Airflow官网资料学习
  14. 把音频中的某个人声去掉_如何把音乐文件里的人声去掉只保留伴奏
  15. 手机电视标准对峙激化
  16. 浅谈欧奈尔对利弗莫尔的继承和发扬
  17. JavaScript正则表达式匹配中英文以及常用标点符号白名单写法
  18. oracle12c生命周期,Oracle 12c 新特性之: ILM 数据生命周期管理
  19. 亚声速 – 超声速等熵喷管流动 数值模拟(文字)
  20. android 杀进程推送服务,关于APP进程被杀死,极光推送收不到消息的解决办法

热门文章

  1. Mysql数据库架构介绍
  2. idea—Lombool插件:实体类不用写set、 get的插件
  3. linux 当前输入法,linux下的输入法
  4. alsa播放结束时的杂音问题
  5. python同或与异或_python中 “与,或,异或”与C语言的不同
  6. cccc天梯赛 2018 赛后总结
  7. 检测两计算机之间是否联通,什么命令测试网络是否联通
  8. 从零开始 verilog 以太网交换机(三)MAC发送控制器的设计与实现
  9. 常用的调用链解决方案
  10. Linux总线pice错误,电脑一直报PCIE BUS错误的原因