图像处理互赞群IT@程序员猿媛

【图像处理】OpenCV系列三十六--- EMD函数详解

2019-05-19  本文已影响32人  307656af5a04

1、函数原型

float EMD(InputArray signature1,
    InputArray signature2,
    int distType,
    InputArray cost = noArray(),
    float *lowerBound = 0,
    OutputArray flow = noArray())

2、函数功能

计算两个加权点配置之间的“最小工作”距离;

该函数计算两个加权点配置之间的土方移动距离和/或距离的下边界;EMD是一个通过修改单纯形算法来解决的运输问题,因此在最坏的情况下,其复杂度是指数级的,但是平均来说,它要快得多;在实际度量的情况下,可以甚至更快地计算下边界(使用线性时间算法),并且可以使用它来粗略确定两个特征是否足够远以使得它们不能与相同的对象相关;

3、参数详解

如果计算出的质心之间的距离大于或等于lowerBound(这意味着特征足够远),则该函数不计算EMD;在任何情况下,lowerBound都设置为返回时质心之间的计算距离;因此,如果要同时计算质心和EMD之间的距离,lowerBound应设置为0;

4、实验实例

#include<iostream>
#include<opencv2\opencv.hpp>
 
using namespace std;
using namespace cv;
 
int main() 
{
    //直方图相似度比较
    vector<Mat> src;//迭代器push_back
    Mat temp = imread("lena.png", 1);
    
    int m=temp.rows / 2;
    int n = temp.cols;
    
    //将一幅图分割为上下两部分
    Mat image_cut =Mat(temp, Rect(0, 0, n, m)).clone();
    Mat image_cut2 = Mat(temp, Rect(0, m, n, m)).clone();
    
    src.push_back(image_cut); 
    src.push_back(image_cut2);
    
    temp = imread("1.png", 1);
    src.push_back(temp);
    
    temp = imread("2.png", 1);
    src.push_back(temp);
 
    // 计算直方图的参数配置
    vector<Mat> hsv(4), hist(4),hist_img(4);
    
    int scale=10,histSize[] = { 8,8 }, ch[] = { 0,1 };
    
    float h_ranges[] = { 0,180 };
    float s_ranges[] = { 0,255 };
    
    const float* ranges[] = { h_ranges,s_ranges };
    
    for (int i = 0; i < 4 ; i++) 
    {
        // 将BGR颜色空间转换为HSV颜色空间
        cvtColor(src[i], hsv[i], COLOR_BGR2HSV);
        
        // 计算直方图
        calcHist(&hsv[i], 1, ch, noArray(), 
            hist[i], 2, histSize, ranges, true);
        
        // 归一化处理
        normalize(hist[i], hist[i], 0, 255, NORM_MINMAX);
        
        // 创建需要显示的图像
        hist_img[i]=Mat::zeros(histSize[0] * scale, 
            histSize[1] * scale, CV_8UC3);
        
        for (int h = 0; h < histSize[0]; h++) 
        {
            for (int s = 0; s < histSize[1]; s++) 
            {
                // 得到像素值
                float hval = hist[i].at<float>(h, s);
                
                // 根据像素值得颜色填充像素值位置
                rectangle(hist_img[i], Rect(h * scale, 
                    s * scale, 10, 10), Scalar::all(hval), -1);
            }
        }
    }
    
    // 显示
    imshow("0", src[0]); 
    imshow("1", src[1]); 
    imshow("2", src[2]); 
    imshow("3", src[3]);
    
    imshow("hist0", hist_img[0]); 
    imshow("hist1", hist_img[1]); 
    imshow("hist2", hist_img[2]); 
    imshow("hist3", hist_img[3]);
    
    for (int i = 0; i < 4; i++)
    {
        cout << "hist[0] vs hist[" << i <<"]"<< endl;
        
        for (int j = 0; j < 4; j++) 
        {
            // 比较两幅直方图的相似度
            cout << "method[" << j <<"]"<< 
                compareHist(hist[0], hist[i], j)<<endl;
        }
    }
 
    // EMD算法 
    vector<Mat> sig(4);
    for (int i = 0; i < 4; i++) 
    {
        vector<Vec3f> sigv;
        
        // 归一化处理
        normalize(hist[i], hist[i], 1, 0, NORM_L1);
        
        for (int h = 0; h < histSize[0]; h++) 
        {
            for (int s = 0; s < histSize[1]; s++) 
            {
                float hval = hist[i].at<float>(h, s);
                
                // 像素值不为0的点存储在sigv
                if (hval != 0)
                    sigv.push_back(Vec3f(hval, (float)h, (float)s));
            }
        }
        
        // 将图像改为单通道,保持原有的行数列数不变
        sig[i] = Mat(sigv).clone().reshape(1);
        
        // 计算EMD
        if (i > 0)
            cout << EMD(sig[0], sig[i], DIST_L2) << endl;
    }
    
    waitKey(0);
    return 0;
}

5、实验结果

我是奕双,现在已经毕业将近两年了,从大学开始学编程,期间学习了C语言编程,C++语言编程,Win32编程,MFC编程,毕业之后进入一家图像处理相关领域的公司,掌握了用OpenCV对图像进行处理,如果大家对相关领域感兴趣的话,可以关注我,我这边会为大家进行解答哦!如果大家需要相关学习资料的话,可以私聊我哦!

上一篇下一篇

猜你喜欢

热点阅读