1. 模型论文:
Global Contrast based Salient Region detection. Ming-Ming Cheng, Niloy J. Mitra, Xiaolei Huang, Philip H. S. Torr, Shi-Min Hu. IEEE TPAMI, 2015
2. 实现代码
(1) 显著性检测公共头文件
#ifndef SALIENTCOMMON_H
#define SALIENTCOMMON_H
// std lib
#include <iostream>
#include <string>
#include <vector>
#include <fstream>// opencv lib
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/ml/ml.hpp>using namespace std;
using namespace cv;#endif // SALIENTCOMMON_H
(2) HC模型.h文件
#ifndef SALIENTHC_H
#define SALIENTHC_H
#include "salientcommon.h"
// Author: HSW
// Date: 2017-11-19
// Global Contrast based Salient Region detection. Ming-Ming Cheng, Niloy J. Mitra, Xiaolei Huang, Philip H. S. Torr, Shi-Min Hu. IEEE TPAMI, 2015
//
// Histgram Contrast Model
class salientHC
{
public:salientHC(Mat& orgImg);~salientHC();void m_getSalientHC(Mat& result);
private:void m_getCompressColor(Mat& rgbImg);void m_getDistancTable();void m_getHistgram(Mat& labImg);
private:Mat m_OrgImg;Mat m_compressColorImg;Mat m_resultImg;unsigned int m_distTable[256];unsigned int m_histTable[3][256];
};#endif // SALIENTHC_H
(3) cpp文件
#include "salienthc.h"
#include "salientcommon.h"salientHC::salientHC(Mat& orgImg)
{orgImg.copyTo(m_OrgImg);memset(m_distTable, 0, sizeof(m_distTable));memset(m_histTable, 0, sizeof(m_histTable));
}salientHC::~salientHC()
{;
}void salientHC::m_getCompressColor(Mat &rgbImg)
{// step 1: Train GMM ModelMat samples[3] = {Mat::zeros(Size(1, rgbImg.rows * rgbImg.cols), CV_32FC1), Mat::zeros(Size(1, rgbImg.rows * rgbImg.cols), CV_32FC1), Mat::zeros(Size(1, rgbImg.rows * rgbImg.cols), CV_32FC1)};unsigned int rowIter, colIter, channelIter, meansIter;int H = rgbImg.rows;int W = rgbImg.cols;for(channelIter = 0; channelIter < 3; ++channelIter){Mat sample = samples[channelIter];for(rowIter = 0; rowIter < H; ++rowIter){for(colIter = 0; colIter < W; ++colIter){sample.at<float>(rowIter*W + colIter, 1) = (float)rgbImg.at<Vec3b>(rowIter, colIter)[channelIter];}}}Mat gmmMeans[3];for(channelIter = 0; channelIter < 3; ++channelIter){Ptr<ml::EM> em_model = ml::EM::create();em_model->setClustersNumber(12);em_model->setCovarianceMatrixType(ml::EM::COV_MAT_SPHERICAL);em_model->setTermCriteria(TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 100, 0.1));em_model->trainEM(samples[channelIter]);gmmMeans[channelIter] = em_model->getMeans();}// step 2: compress Colorm_compressColorImg = Mat::zeros(rgbImg.size(), CV_8UC3);for(channelIter = 0; channelIter < 3; ++channelIter){for(rowIter = 0; rowIter < H; ++rowIter){for(colIter = 0; colIter < W; ++colIter){unsigned int singleChannelVal = rgbImg.at<Vec3b>(rowIter, colIter)[channelIter];float minDistMean = 0;float minDist = 9999999;for(meansIter = 0; meansIter < 12; ++meansIter){if(abs(singleChannelVal - gmmMeans[channelIter].at<double>(meansIter, 1)) < minDist){minDist = abs(singleChannelVal - gmmMeans[channelIter].at<double>(meansIter, 1));minDistMean = gmmMeans[channelIter].at<double>(meansIter, 1);}}unsigned int means = cvRound(minDistMean);m_compressColorImg.at<Vec3b>(rowIter, colIter)[channelIter] = means;}}}
}void salientHC::m_getDistancTable()
{int iter;for(iter = 0; iter < 256; ++iter){m_distTable[iter] = iter;}
}void salientHC::m_getHistgram(Mat &labImg)
{int rowIter, colIter, channelIter;int H = labImg.rows;int W = labImg.cols;for(rowIter = 0; rowIter < H; ++rowIter){for(colIter = 0; colIter < W; ++colIter){for(channelIter = 0; channelIter < 3; ++channelIter){int labVal = labImg.at<Vec3b>(rowIter, colIter)[channelIter];m_histTable[channelIter][labVal] += 1;}}}}void salientHC::m_getSalientHC(Mat &result)
{Mat tmpRgbImg;if(m_OrgImg.channels() == 1){cvtColor(m_OrgImg, tmpRgbImg, CV_GRAY2RGB);}else if(m_OrgImg.channels() == 3){cvtColor(m_OrgImg, tmpRgbImg, CV_BGR2RGB);}// RGB Color Compress Colorsm_getCompressColor(tmpRgbImg);// RGB Color space To Lab Color SpaceMat tmpLabImg;cvtColor(m_compressColorImg, tmpLabImg, CV_RGB2Lab);tmpLabImg.convertTo(tmpLabImg, CV_8U);// Cal. Color Distance Tablem_getDistancTable();// Cal. Histgramm_getHistgram(tmpLabImg);// Cal. Salient Mapint rowIter, colIter, channelIter, histIter;int H = m_compressColorImg.rows;int W = m_compressColorImg.cols;// Cal. Search Tabledouble salientTable[3][256] = {0};for(channelIter = 0; channelIter < 3; ++channelIter){for(histIter = 0; histIter < 256; ++histIter){if(m_histTable[channelIter][histIter]){int iter;for(iter = 0; iter < 256; ++iter){if(m_histTable[channelIter][iter]){int gap = abs(histIter - iter);salientTable[channelIter][histIter] = m_histTable[channelIter][iter] * m_distTable[gap];}}}}}Mat tmpSalientImg = Mat::zeros(Size(W,H), CV_32FC1);m_resultImg = Mat::zeros(Size(W,H), CV_32FC1);for(rowIter = 0; rowIter < H; ++rowIter){for(colIter = 0; colIter < W; ++colIter){for(channelIter = 0; channelIter < 3; ++channelIter){tmpSalientImg.at<float>(rowIter, colIter) += salientTable[channelIter][tmpLabImg.at<Vec3b>(rowIter, colIter)[channelIter]];}}}// fine salient mapGaussianBlur(tmpSalientImg, tmpSalientImg, Size(5,5), 5);double minVal = 0, maxVal = 0;minMaxLoc(tmpSalientImg, &minVal, &maxVal);double scale = 255./(maxVal - minVal);double shift = -minVal * scale;convertScaleAbs(tmpSalientImg, m_resultImg, scale, shift);m_resultImg.copyTo(result);
}
3. 测试代码:
#include "salientcommon.h"
#include "salientlc.h"
#include "salientitti.h"
#include "salientft.h"
#include "salientsr.h"
#include "salientpft.h"
#include "salienthc.h"#define TEST_LC (1)
#define TEST_ITTI (2)
#define TEST_FT (3)
#define TEST_RS (4)
#define TEST_PFT (5)
#define TEST_HC (6)
#define TEST_VIDEO (100)#define TEST_MODEL (6)int main()
{
#if TEST_MODEL == TEST_LCMat inputImg = imread("test7.jpg");if(inputImg.empty()){cout << "Read Image Failed " << endl;return -1;}imshow("Org-Img", inputImg);waitKey(20);salientLC salientLCObj(inputImg);Mat resultImg;salientLCObj.m_getSalientLC(resultImg);imshow("LC-Result", resultImg);waitKey(0);return 0;#elif TEST_MODEL == TEST_ITTIstring imageName = "test2.jpg";Mat resultImg;salientITTI salientITTIObj(imageName);salientITTIObj.m_getSalientITTI(resultImg);imshow("ITTI-Result", resultImg);waitKey(0);return 0;#elif TEST_MODEL == TEST_FTMat inputImg = imread("test7.jpg");if(inputImg.empty()){cout << "Read Image Failed " << endl;return -1;}imshow("Org-Img", inputImg);waitKey(20);salientFT salientFTObj(inputImg);Mat resultImg;salientFTObj.m_getSalientFT(resultImg);imshow("FT-Result", resultImg);waitKey(0);return 0;
#elif TEST_MODEL == TEST_RSMat inputImg = imread("test7.jpg");if(inputImg.empty()){cout << "Read Image Failed " << endl;return -1;}imshow("Org-Img", inputImg);waitKey(20);salientSR salientSRObj(inputImg);Mat resultImg;salientSRObj.m_getSalientSR(resultImg);imshow("RS-Result", resultImg);waitKey(0);return 0;
#elif TEST_MODEL == TEST_PFTMat inputImg = imread("test1.jpg");if(inputImg.empty()){cout << "Read Image Failed " << endl;return -1;}imshow("Org-Img", inputImg);waitKey(20);salientPFT salientPFTObj(inputImg);Mat resultImg;salientPFTObj.m_getSalientPFT(resultImg);imshow("PFT-Result", resultImg);waitKey(0);return 0;
#elif TEST_MODEL == TEST_HCMat inputImg = imread("test6.jpg");if(inputImg.empty()){cout << "Read Image Failed " << endl;return -1;}imshow("Org-Img", inputImg);waitKey(20);salientHC salientHCObj(inputImg);Mat resultImg;salientHCObj.m_getSalientHC(resultImg);imshow("HC-Result", resultImg);waitKey(0);return 0;
#elif TEST_MODEL == TEST_VIDEOstring fileName = "testVideo4.yuv";ifstream ifstr(fileName, ios_base::in | ios_base::binary);if(!ifstr.is_open()){cout << "Open file Failed " << endl;return -1;}Mat yuvFrame;int frameHeight = 144;int frameWidth = 176;int yuvFrameSize = frameHeight * frameWidth * 3 / 2;yuvFrame.create(Size(frameWidth, frameHeight * 3 / 2), CV_8UC1);char* buffer = new char[yuvFrameSize];Mat rgbFrame;rgbFrame.create(Size(frameWidth, frameHeight), CV_8UC3);Mat meanLogMag;int count = 0;int isMeansFlag = 0;while(1){memset(buffer, 0, yuvFrameSize);ifstr.read(buffer, yuvFrameSize * sizeof(unsigned char));if(ifstr.gcount() != yuvFrameSize){cout << "Read file End or Failed " << endl;ifstr.close();delete []buffer;return -1;}memcpy(yuvFrame.data, buffer, yuvFrameSize);cvtColor(yuvFrame, rgbFrame, CV_YUV2BGR_I420);if(count == 0){Mat grayFrame;cvtColor(rgbFrame, grayFrame, CV_BGR2GRAY);equalizeHist(grayFrame,grayFrame);Mat tmpPaddingImg;Mat tmpOrgImg;grayFrame.copyTo(tmpOrgImg);// Get FFT2 Factorysint M = getOptimalDFTSize(tmpOrgImg.rows);int N = getOptimalDFTSize(tmpOrgImg.cols);copyMakeBorder(tmpOrgImg, tmpPaddingImg, 0, M - tmpOrgImg.rows, 0, N - tmpOrgImg.cols, BORDER_CONSTANT, Scalar(0));if(meanLogMag.empty()){cout << "run here " << endl;meanLogMag = Mat::zeros(Size(N,M), CV_32FC1);}// FFT2 TranslateMat planes[2];tmpPaddingImg.convertTo(tmpPaddingImg, CV_32F);planes[0] = tmpPaddingImg;planes[1] = Mat::zeros(tmpPaddingImg.size(), CV_32F);Mat tmpComplexImg;merge(planes, 2, tmpComplexImg);dft(tmpComplexImg, tmpComplexImg);split(tmpComplexImg, planes);// compute phaseMat tmpPhaseImg;phase(planes[0], planes[1], tmpPhaseImg);// compute log abs MagnitudeMat tmpMagImg;magnitude(planes[0], planes[1], tmpMagImg);// compute sin & cosionMat tmpSin, tmpCosion;cv::divide(planes[0], tmpMagImg, tmpCosion); // Re partcv::divide(planes[1], tmpMagImg, tmpSin); // Im PartMat tmpLogMagImg;cv::log(tmpMagImg, tmpLogMagImg);cv::add(tmpLogMagImg, meanLogMag, meanLogMag);}else{if(isMeansFlag == 0){int rowIter, colIter;for(rowIter = 0; rowIter < meanLogMag.rows; ++rowIter){for(colIter = 0; colIter < meanLogMag.cols; ++colIter){meanLogMag.at<float>(rowIter, colIter) = meanLogMag.at<float>(rowIter, colIter) * 1.0 / count;}}GaussianBlur(meanLogMag, meanLogMag, Size(5,5), 3);isMeansFlag = 1;}Mat grayFrame;cvtColor(rgbFrame, grayFrame, CV_BGR2GRAY);equalizeHist(grayFrame,grayFrame);Mat tmpPaddingImg;Mat tmpOrgImg;grayFrame.copyTo(tmpOrgImg);// Get FFT2 Factorysint M = getOptimalDFTSize(tmpOrgImg.rows);int N = getOptimalDFTSize(tmpOrgImg.cols);copyMakeBorder(tmpOrgImg, tmpPaddingImg, 0, M - tmpOrgImg.rows, 0, N - tmpOrgImg.cols, BORDER_CONSTANT, Scalar(0));// FFT2 TranslateMat planes[2];tmpPaddingImg.convertTo(tmpPaddingImg, CV_32F);planes[0] = tmpPaddingImg;planes[1] = Mat::zeros(tmpPaddingImg.size(), CV_32F);Mat tmpComplexImg;merge(planes, 2, tmpComplexImg);dft(tmpComplexImg, tmpComplexImg);split(tmpComplexImg, planes);// compute phaseMat tmpPhaseImg;phase(planes[0], planes[1], tmpPhaseImg);// compute log abs MagnitudeMat tmpMagImg;magnitude(planes[0], planes[1], tmpMagImg);// compute sin & cosionMat tmpSin, tmpCosion;cv::divide(planes[0], tmpMagImg, tmpCosion); // Re partcv::divide(planes[1], tmpMagImg, tmpSin); // Im PartMat tmpLogMagImg;cv::log(tmpMagImg, tmpLogMagImg);// Spectral ResidualMat tmpResidualImg;cv::subtract(tmpLogMagImg, meanLogMag, tmpResidualImg);// IFFT2 Translatecv::exp(tmpResidualImg, tmpResidualImg);Mat tmpRel, tmpIm;cv::multiply(tmpCosion, tmpResidualImg, tmpRel);cv::multiply(tmpSin, tmpResidualImg, tmpIm);planes[0] = tmpRel;planes[1] = tmpIm;merge(planes, 2, tmpComplexImg);Mat tmpSalientImg;dft(tmpComplexImg, tmpSalientImg, DFT_INVERSE);// Normalizesplit(tmpSalientImg, planes);magnitude(planes[0], planes[1], tmpMagImg);GaussianBlur(tmpMagImg, tmpMagImg, Size(7,7), 3);double minVal = 0, maxVal = 0;minMaxLoc(tmpMagImg, &minVal, &maxVal);double scale = 255./(maxVal - minVal);double shift = -minVal * scale;Mat salient;convertScaleAbs(tmpMagImg(Rect(0,0,tmpOrgImg.cols, tmpOrgImg.rows)), salient, scale, shift);imshow("Detect-map", salient);waitKey(25);}imshow("Org-map", rgbFrame);waitKey(25);count++;}
#elsecout << "Not Support !" << endl;return 0;
#endif
}
4. 测试效果