Bootstrap

基于边缘检测(Canny算子)和颜色特征的图像检索系统(含源码)OpenCV+QT+MySQL【C++】

分享本科毕业设计的项目,完整代码在文章底部

一个基于颜色特征和边缘检测(采用Canny边缘检测算子)的图像检索系统。以C++作为开发语言,Qt5.12作为主要开发框架进行界面设计,OpenCV4.4作为开发工具库,使用MySQL数据库设计和实现系统的各项功能。

程序运行之前应确保成功安装MinGW x64版本的Qt(5.12及以上)及Qt Creator(Community),在Qt中使用CMake配置OpenCV(4.4及以上),安装并调试MySQL数据库。

在Qt Creator中构建并运行项目,验证数据库成功连接后可上传图像进行测试。

​​​​​​​

颜色特征是图像检索领域中使用最为广泛的特征。大部分图像都含有丰富的颜色信息,即使是灰度图像也有着丰富的灰度等级分布。使用颜色特征在判断差异性和相似性时,不仅方便、效果好,执行速度也比较快。边缘特征是介于纹理特征和形状特征之间的一类图像特征,对于图像内容的区域性表达也很有代表性。同颜色特征一样,边缘特征的提取也比较方便,已经有包括Roberts算子、Sobel算子、Prewitt算子、LOG算子、Canny算子等在内的多种成熟的提取方法。

因颜色特征和边缘特征的优势所在,本文的图像检索方法设计拟将这两种特征作为融合处理的基本特征。其中,边缘特征采用Canny边缘检测算子进行处理,这是因为相比传统的微分算子,Canny算子是当前最优化且最受推崇的一种微分算子。而OpenCV也提供了一个相当便捷的边缘接口Canny函数(Canny()),对图像使用高斯滤波函数(GaussianBlur())后,再通过Canny函数转换即可得到相应的边缘检测之后的图像。

具体的操作步骤是:

(1)调用函数cvtColor(image1, image2,CV_BGR2HSV)将原始待检索图像与数据库中的图像从RGB空间转换到HSV空间。

(2)调用函数calcHist(&image, 1, channels, Mat(), hist_base, 2, histsize, histRanges, true, false)计算直方图,其中image为传入图像。

(3)调用函数 normalize(hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat())进行归一化处理。

(4)调用函数compareHist(hist_base, hist_base, CV_COMP_BHATTACHARYYA)进行相关性比较,并返回结果值。

(5)将上一步所返回的结果值存入数据库,与文件路径相对应,方便查询和调取。

(6)因经相关性比较计算所得值越小,说明图像之间差异性越小,即两图越相似。所以采取升序查询的方式将颜色特征相似值最低的前八张图显示在用户界面上。

代码:

if(ui->radioButton_color->isChecked()){

        std::vector <cv::String> filelist_color;
        std::vector <cv::String> finallist_color;
        QString qstr_1;
        QString qstr_2;
        QSqlQuery query_color_pre;
        QSqlQuery query_color;
        QSqlQuery query_color_final;
        std::vector <cv::Mat> convertlist;
        std::vector <cv::Mat> HSVlist;
//        std::vector <similarityInfo> color_list;

//        std::vector <cv::String> Simlist;

        query_color_pre.exec( "select * from image_address" );
        if(!query_color_pre.exec()){
            QMessageBox::information(this,"Warning",query_color_pre.lastError().text());
        }else{

        QMessageBox::information(this,"Method","Color-Based");
        while(query_color_pre.next())
                {
                     qstr_1 = query_color_pre.value(1).toString();
                     filelist_color.push_back(qstr_1.toStdString());
                }

        for (auto &i : filelist_color) {
            cout<<i<<endl;
            convertlist.push_back(imread(i,cv::IMREAD_REDUCED_COLOR_4));

        }

        if (!base.data)
        {
            QMessageBox::information(this,"Warning","Base image load faild.");
        }

        Mat HSVbase;
        //步骤一:从RGB空间转换到HSV空间
        cvtColor(base, HSVbase, CV_BGR2HSV);

        for (auto &i : convertlist) {
            Mat HSVtemp;
            cvtColor(i, HSVtemp, CV_BGR2HSV);
            HSVlist.push_back(HSVtemp);
        }

        int h_bins = 50;
        int s_bins = 60;
        int histsize[] = { h_bins,s_bins };
        //hue varies from 0 to 179,saturation from 0 to 255
        float h_ranges[] = { 0,180 };
        float s_ranges[] = { 0,256 };
        const float*histRanges[] = { h_ranges,s_ranges };
        //use the 0-th and 1-st channels
        int channels[] = { 0,1 };

        MatND hist_base;
        MatND hist_test;

        //计算直方图
        calcHist(&HSVbase, 1, channels, Mat(), hist_base, 2, histsize, histRanges, true, false);
        normalize(hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat());//归一化

        int k=0;
        double Simlist[filelist_color.size()];
        for (auto &i : HSVlist)
        {
            calcHist(&i, 1, channels, Mat(), hist_test, 2, histsize, histRanges, true, false);


        //归一化

            normalize(hist_test, hist_test, 0, 1, NORM_MINMAX, -1, Mat());

        //步骤三:比较直方图,并返回值
            double similarity = compareHist(hist_base, hist_test, CV_COMP_BHATTACHARYYA);
            Simlist[k]=similarity;
            cout<<Simlist[k]<<endl;
            query_color.prepare("update image_address set similarity_color=? where filename=?");
            query_color.addBindValue(Simlist[k]);
//            QVariant var;
//            var.setValue(filelist_color[k]);
//            query_color.addBindValue(var);
            query_color.addBindValue(QString(QString::fromLocal8Bit(filelist_color[k].c_str())));
            query_color.exec();

//          QString sql = "insert ignore into image_address(similarity) values(:similarity)";

            k++;

    }

        query_color_final.exec( "select * from image_address order by similarity_color asc" );

//---------------------------------------------------------------------
        while(query_color_final.next())
                {
                     qstr_2 = query_color_final.value(1).toString();
                     finallist_color.push_back(qstr_2.toStdString());

                }

        for (auto &i : finallist_color) {
            cout<<i<<endl;}
}

 

具体的操作步骤是:

(1)进行边缘检测前需先将图像进行灰度化处理。

调用函数cvtColor(image1, image2,COLOR_BGR2GRAY)将原始待检索图像与数据库中的图像进行颜色空间转换,输出的image2即为完成灰度化转换的图像。

(2)调用函数GaussianBlur(base_gray, base_blurred, cv::Size(3, 3), 3);将灰度图进行高斯滤波器平滑处理,目的是尽可能去除噪声。其中内核的大小Size(w, h)必须是正奇数对。

(3)调用函数Canny(base_blurred, base_edge, Min_Threshold, Max_Threshold)进行基于Canny算子的边缘检测,其中Min_Threshold为最低阈值Max_Threshold为最高阈值。低于最低阈值的像素点将不会被认为是边缘;高于最高阈值的像素点则会被认为是边缘;介于最低阈值和最高阈值之间的像素点需要进行进一步判断,当其与所得到的边缘像素点相邻才被认为是边缘。本文所设计的系统将这两个阈值设置成了可输入调节的模式,通过参数传递用户可以自定义键入最低阈值和最高阈值来达到所需的边缘检测效果。如当待检索图像纹理细节较为丰富时,用户可适当调高阈值,当待检索图像构成线条较为简明时,用户可适当降低阈值以获得理想的检索效果。

(4)调用sift->detect(image, keypoints)检测特征点。调用sift->compute(image, keypoints, descriptors1)计算特征描述符。

(5)调用函数cv::Ptr<cv::DescriptorMatcher>matcher=cv::DescriptorMatcher::create

(cv::DescriptorMatcher::BRUTEFORCE)进行特征匹配。

(6)t1 = cv::getTickCount();

  matcher->match(descriptors1, descriptors2,

;