Compute correlation of two Mat files in OpenCV - c++

I have got a vector of Mat files and I want to calculate the correlation between them so as to keep the two mat files with which are theoretical similar. Actually in this vector are stored detected eyes from images, so I am trying to delete outliers. How is it possible to calculate correlation between two Mat files???
EDIT:
Mat Detection::hist_calculation(Mat image){
// Establish the number of bins
int histSize = 256;
// Set the ranges
float range[] = { 0, 256 } ;
const float* histRange = { range };
bool uniform = true; bool accumulate = false;
Mat hist;
// Compute the histograms:
calcHist( &image, 1, 0, Mat(), hist, 1, &histSize, &histRange, uniform, accumulate );
// Draw the histograms for B, G and R
int hist_w = 512; int hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );
normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
for( int i = 1; i < histSize; i++ )
{
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(hist.at<float>(i)) ) ,
Scalar( 255, 0, 0), 2, 8, 0 );
}
//// Display
//namedWindow("calcHist Demo", CV_WINDOW_AUTOSIZE );
//imshow("calcHist Demo", histImage );
//waitKey(0);
return hist;
}
double Detection::cvMatHistCorrelation(Mat file1, Mat file2) {
cvtColor(file1, file1, CV_BGR2GRAY); cvtColor(file2, file2, CV_BGR2GRAY);
Mat hist1 = hist_calculation(file1);
Mat hist2 = hist_calculation(file2);
double autoCorrelation1 = compareHist( hist1, hist1, CV_COMP_BHATTACHARYYA );
double autoCorrelation2 = compareHist( hist1, hist1, CV_COMP_BHATTACHARYYA );
double correlation = compareHist( hist1, hist2, CV_COMP_BHATTACHARYYA );
cout << "autocorrelation of his1: "<< autoCorrelation1 << endl;
cout << "autocorrelation of hist2: "<< autoCorrelation2 << endl;
cout << "correlation between hist1 and hist2: "<< autoCorrelation << endl;
return correlation;
}
I think it works fine.

It's better to compute the correlation of feature vectors of these two Mat files instead of on the Mat data directly.
For example, you can first compute RGB/HSV color histogram (24d vector if use 8-bins for each channel) for each Mat file and then compute correlation of these two histogram vectors.

Related

Merging two 1d histograms into one

I got two histograms which I created with standard openCV function calcHist:
int getModels(string filename) {
Mat src = imread(filename, 1);
if(!src.data) { return -1; }
Mat imageHSV;
cvtColor(src, imageHSV, COLOR_BGR2HSV);
vector<Mat> bgr_planes;
split(imageHSV, bgr_planes);
int histSize = 256;
float range[] = { 0, 256 } ;
const float* histRange = { range };
bool uniform = true; bool accumulate = false;
Mat g_hist, r_hist;
calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate );
cv::Mat combined_hist = g_hist + r_hist;
int hist_w = 512; int hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage(hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );
for( int i = 0; i < histSize; i++ )
{
line( histImage, Point( bin_w*(i-1), cvRound(combined_hist.at<float>(i-1)) ) ,
Point( bin_w*(i), cvRound(combined_hist.at<float>(i)) ),
Scalar( 19,90,87), 2, 8, 0 );
}
/// Display
namedWindow(filename, CV_WINDOW_AUTOSIZE );
imshow(filename, histImage );
return 0;
}
Is there any way to merge them into one combined_hist histogram?
Yes, you can. OpenCV has cv::add which can be used like this:
cv::Mat combined_hist;
cv::add(g_hist, r_hist, combined_hist);
However, since cv::Mat has overloaded operators, you can just do this:
cv::Mat combined_hist = g_hist + r_hist;
Hope that helps you.

Automatic detection of dominant intensity area in an image

I need some help in detecting the dominant intensity area of an image. Suppose I have the following images and I like to automatically detect the dominant intensity area and find the mean/average intensity value of that dominant area.
Here, in Image-1, the dominant intensity area is the area with light gray color and in Image-2, the dominant area is with the dark gray color. How can I detect the dominant areas in those images and find the mean intensity value of the dominant area.
Image-1:
Image-2:
Any suggestion will be helpful!
Update: I used the following codes to get the histogram for Image-2. Figure-3 shows the histogram. Now, I need to find out which bin holds the most of the values i.e. the mode of the histogram. But, couldn't figure out how to calculate the bin with most of the values.
Figure-3:
int main(int, char**)
{
Mat gray=imread("Depth_frames_27/Image23.png",0);
namedWindow( "Gray", 1 ); imshow( "Gray", gray );
// Initialize parameters
int histSize = 256; // bin size
float range[] = { 0, 255 };
const float *ranges[] = { range };
// Calculate histogram
MatND hist;
calcHist( &gray, 1, 0, Mat(), hist, 1, &histSize, ranges, true, false );
double minVal=0, maxVal=0;
minMaxLoc(hist, &minVal, &maxVal, 0, 0);
// cout<<"Max:"<<maxVal<<endl;
// cout<<"Min:"<<minVal<<endl;
// Show the calculated histogram in command window
double total;
total = gray.rows * gray.cols;
for( int h = 0; h < histSize; h++ )
{
float binVal = hist.at<float>(h);
cout<<" "<<binVal;
}
// Plot the histogram
int hist_w = 512; int hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage( hist_h, hist_w, CV_8UC1, Scalar( 0,0,0) );
normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
for( int i = 1; i < histSize; i++ )
{
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(hist.at<float>(i)) ),
Scalar( 255, 0, 0), 2, 8, 0 );
}
namedWindow( "Result", 1 ); imshow( "Result", histImage );
waitKey();
return 0;
}
Update-2: Worked out finally! I did the following to get the location and value of the maximum bin of the histogram.
double minVal=0, maxVal=0; int minIdx, maxIdx;
minMaxIdx(hist,&minVal,&maxVal, &minIdx, &maxIdx);
cout<<"Max:"<<maxVal<<endl;
cout<<"MaxIdx:"<<maxIdx<<endl;
The MaxIdx gives the location of the highest bin of the histogram and that's the dominant intensity value for the image!
What you are after is the mode of the histogram of intensities (the bin with the highest frequency). It directly tells you the average intensity.
For the given images, the histogram is made of two perfectly sharp peaks.
In some bad cases, the main peak can be spread over several secondary peaks. In such cases, you need to apply smoothing to the histogram before taking the mode.
It can be interesting to look at the relative heights of the first and second maxima, to check how dominant the color is.

Number plate localization in bulk of images

I have got bulk of car images and want to perform automatic number plate recognition but i am stuck at localization phase .I want to get license plate individually as output on which i can perform recognition.Here is my code for localization:
int main(int args,char* argv)
{
//String filename;
//filename="";
cv::Mat image=cv::imread("C:\\Users\\Sarora\\Downloads\\Images\\frame_1375.jpg",CV_LOAD_IMAGE_COLOR);
cv::Mat img;
cv::Mat img_sobel;
cv::Mat grad_x, grad_y;
cv::Mat abs_grad_x, abs_grad_y;
cv::Mat imgContours;
//vector <Plate>result;
cv::cvtColor(image, img, CV_BGR2GRAY);
blur(img, img, cv::Size(5,5));
//cv::namedWindow("Img1.jpg", CV_WINDOW_AUTOSIZE );
//sobel filter applied on image..............................................................................................
cv::Sobel(img, grad_x, CV_16S, 1, 0,3,1,0, cv::BORDER_DEFAULT);
convertScaleAbs( grad_x, abs_grad_x );
cv::Sobel(img, grad_y, CV_16S, 0, 1,3,1,0, cv::BORDER_DEFAULT);
convertScaleAbs( grad_y, abs_grad_y );
addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, img_sobel );
cv::imwrite("Img2.jpg",img_sobel);
//Threshold the image...................................................................................................................
cv::Mat Thresh_img;
threshold(img_sobel, Thresh_img, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY);
//imshow("Threshold", Thresh_img);
//Morphological close operation applied................................................................................................
cv::Mat element1=cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
cv::morphologyEx(Thresh_img,Thresh_img,CV_MOP_CLOSE,element1);
cv::imwrite("Close1.jpg",Thresh_img);
//cv::waitKey(5000);
//find Contours of whole image......................................................................................................
std::vector <std::vector<cv::Point>> contours;
cv::findContours(Thresh_img, contours,CV_RETR_LIST,CV_CHAIN_APPROX_NONE);
//cv::drawContours(image,contours,-1,cv::Scalar(0,0,255),3);
cv::imwrite("Contours1.jpg",image);
std::vector <std::vector<cv::Point>>::iterator itc= contours.begin();
std::vector <cv::RotatedRect> rects;
//vector<vector<Point> > contours_poly(rects.size());
//vector<Rect> boundRect(rects.size());
//Remove patch not inside the limits of aspect ratio and area..................................................................................
while (itc!=contours.end()) {
cv::RotatedRect mr= cv::minAreaRect(cv::Mat(*itc));
if( !verifySizes(mr))
{ itc= contours.erase(itc);
}else {
++itc;
rects.push_back(mr);
}
}
cv::Mat drawing;
vector<vector<cv::Point> > contours_poly(rects.size());
vector<cv::Rect> boundRect(rects.size());
//Draw contours
cv::Mat output;
image.copyTo(output);
for(int i=0;i<rects.size();i++)
{
approxPolyDP(cv::Mat(contours[i]), contours_poly[i], 10, true);
boundRect[i] = cv::boundingRect(cv::Mat(contours_poly[i]));
}
//cv::imwrite("Contours.jpg", output);
for (int i = 0; i < rects.size(); i++)
{
drawContours(output, contours_poly, i, CV_RGB(255, 255, 255), 1, 8, vector<cv::Vec4i>(), 0, cv::Point());
//rectangle(output, boundRect[i].tl(), boundRect[i].br(), CV_RGB(0, 255, 0), 3, 8, 0);
}
cv::imwrite("drawing1.jpg",output);
}
bool verifySizes(cv::RotatedRect mr){
float error=0.4;
//Set a min and max area. All other patches are discarded
int min= 5; // minimum area
int max=1000; // maximum area
//Get only patches that match
float rmin= 1;
float rmax= 10;
int area= mr.size.height * mr.size.width;
float r= (float)mr.size.width / (float)mr.size.height;
if(r<1)
r= (float)mr.size.height / (float)mr.size.width;
if(( area < min || area > max ) || ( r < rmin || r > rmax )){
return false;
}else{
return true;
}
}
I have performed sobel filter,Threshold(OTSU+binary),Morphological operation CLOSE,findContours(),removal of one not inside limits of area and aspect ratio and approxPolyDP on the imageThis is my input image
This is approxPolyDP image
Problem is output image is not forming rectangles around License plate.Can anyone tell what is wrong in the code and also how can i proceed further to automatically find license plates in bulk of images?I am confused.
Thank you

calculating cumulative histogram

I want to calculate the cumulative histogram , I have done the histogram calculation and below is the code for it.
I have converted the iamge to ycbcr channel and applied histogram for Y channel
Thanks for help
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "iostream"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
void histogramcalculation(const Mat &Image, Mat &histoImage)
{
int histSize = 255;
// Set the ranges ( for B,G,R) )
float range[] = { 0, 256 } ;
const float* histRange = { range };
bool uniform = true; bool accumulate = false;
Mat b_hist, g_hist, r_hist;
vector<Mat> bgr_planes;
split(Image, bgr_planes );
// Compute the histograms:
calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );
// Draw the histogram
int hist_w = 512; int hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );
// Normalize the result to [ 0, histImage.rows ]
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
// Draw
for( int i = 1; i < histSize; i++ )
{
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float> (i-1)) ) , Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ), Scalar( 255, 0, 0), 2, 8, 0 );
}
histoImage= histImage;
}
int main( )
{
Mat src, imageq,ycbcr;
Mat histImage;
// Read original image
src = imread( "3.jpg");
if(! src.data )
{ printf("Error imagen\n"); exit(1); }
cvtColor(src, ycbcr, CV_RGB2YCrCb);
vector <Mat> planes;
split(ycbcr,planes);
// Separate the image in 3 places ( B, G and R )
// Display results
imshow( "Source image", src );
// Calculate the histogram to each channel of the source image
histogramcalculation(planes[0], histImage);
// Display the histogram for each colour channel
imshow("Colour Image Histogram", histImage );
// Wait until user exits the program
waitKey();
return 0;
}
OpenCV cv::calcHist has the accumulate flag, but that doesn't do a cummulative histogram, it just doesn't set the histogram to zero at the beginning, so you can accumulate histograms over multiple images.
What you want to do, is after getting the histogram, just accumulate it yourself by adding the sum of all previous histogram bins to every bin.
cv::Mat hist;
cv::calcHist(&eyeROI, 1, 0, Mat(), hist, 1, &histSize, &histRange);
cv::Mat accumulatedHist = hist.clone();
for (int i = 1; i < histSize; i++) {
accumulatedHist.at<float>(i) += accumulatedHist.at<float>(i - 1);
std::cout << "Accumulated : " << accumulatedHist.at<float>(i) << ", original = " << hist.at<float>(i) << std::endl;
}
std::cout added so you can look at the result.

Histogram for green component of an image in c++ using OpenCV

I want to create a histogram for an green component of an image in c++ using OpenCV.
The following code is working fine for color image but once i split the image into its RGB component and using the green component to call calcHist function, I am getting the following error.
OpenCV Error: Assertion failed (j < nimages) in histPrepareImages, file /root/src/OpenCV-2.4.1/modules/imgproc/src/histogram.cpp, line 148
terminate called after throwing an instance of 'cv::Exception'
what(): /root/src/OpenCV-2.4.1/modules/imgproc/src/histogram.cpp:148: error: (-215) j < nimages in function histPrepareImages
Aborted (core dumped)
Here is my code for the same.
I took two images to create the histogram. Anyone pls help so solve this problem.
#include <cv.h>
#include <highgui.h>
using namespace cv;
int main( int argc, char** argv )
{
Mat src,src1, hsv, hsv1;
if( argc != 3 || !(src=imread(argv[1], 1)).data || !(src=imread(argv[2], 1)).data)
return -1;
std::vector<cv::Mat> three_channels;
cv::split(src,three_channels);
std::vector<cv::Mat> three_channels1;
cv::split(src1,three_channels1);
//cvtColor(src, hsv, CV_BGR2HSV);
//cvtColor(src1, hsv1, CV_BGR2HSV);
// Quantize the hue to 30 levels
// and the saturation to 32 levels
int hbins = 30, sbins = 32;
int histSize[] = {hbins, sbins};
// hue varies from 0 to 179, see cvtColor
float hranges[] = { 0, 180 };
// saturation varies from 0 (black-gray-white) to
// 255 (pure spectrum color)
float sranges[] = { 0, 256 };
const float* ranges[] = { hranges, sranges };
MatND hist, hist1, difference;
// we compute the histogram from the 0-th and 1-st channels
int channels[] = {0, 1};
calcHist( &three_channels[1], 1, channels, Mat(), // do not use mask
hist, 2, histSize, ranges,
true, // the histogram is uniform
false );
calcHist( &three_channels1[1], 1, channels, Mat(), // do not use mask
hist1, 2, histSize, ranges,
true, // the histogram is uniform
false );
double maxVal=0;
minMaxLoc(hist, 0, &maxVal, 0, 0);
minMaxLoc(hist1, 0, &maxVal, 0, 0);
int scale = 10;
Mat histImg = Mat::zeros(sbins*scale, hbins*10, CV_8UC3);
Mat hist1Img = Mat::zeros(sbins*scale, hbins*10, CV_8UC3);
Mat hist2Img = Mat::zeros(sbins*scale, hbins*10, CV_8UC3);
double hist_diff =0;
hist_diff = compareHist(hist, hist1, CV_COMP_CORREL);
absdiff(hist, hist1, difference);
printf("\nHist Diff: %f\n", hist_diff);
for( int h = 0; h < hbins; h++ )
for( int s = 0; s < sbins; s++ )
{
float binVal = hist.at<float>(h, s);
int intensity = cvRound(binVal*255/maxVal);
rectangle( histImg, Point(h*scale, s*scale),
Point( (h+1)*scale - 1, (s+1)*scale - 1),
Scalar::all(intensity),
CV_FILLED );
}
for( int h = 0; h < hbins; h++ )
for( int s = 0; s < sbins; s++ )
{
float binVal = hist1.at<float>(h, s);
int intensity = cvRound(binVal*255/maxVal);
rectangle( hist1Img, Point(h*scale, s*scale),
Point( (h+1)*scale - 1, (s+1)*scale - 1),
Scalar::all(intensity),
CV_FILLED );
}
for( int h = 0; h < hbins; h++ )
for( int s = 0; s < sbins; s++ )
{
float binVal = difference.at<float>(h, s);
int intensity = cvRound(binVal*255/maxVal);
rectangle( hist2Img, Point(h*scale, s*scale),
Point( (h+1)*scale - 1, (s+1)*scale - 1),
Scalar::all(intensity),
CV_FILLED );
}
namedWindow( "Source", 1 );
imshow( "Source", src );
namedWindow( "H-S Histogram", 1 );
imshow( "H-S Histogram", histImg );
namedWindow( "H-S Histogram1", 1 );
imshow( "H-S Histogram1", hist1Img );
namedWindow( "H-S Histogram2", 1 );
imshow( "H-S Histogram2", hist2Img );
waitKey();
}
You're trying to calculate the histogram of two channels (0 and 1) from an image that has only one channel, as you splitted it.
I did not look at your code in detail, but I guess you could omit the splitting and pass src/src1 to calcHist instead of three_channels[1]/three_channels1[1], setting channels = {1}
EDIT
In your code, change channels = {0,1} to channels{0}, you should not get any errors.
You're passing a single-channel image to calcHist(), that's why you should only use channel 0 (the only one). By passing three_channels[1] as input image, you're making sure that you're actually analysing the second channel of your input image.
OR do the following:
int channels[] = {1};
calcHist( &src, 1, channels, Mat(), // do not use mask
hist, 2, histSize, ranges,
true, // the histogram is uniform
false );
You don't need to cv::split(src,three_channels) anymore.
That's two versions that compile, but you actually want to compute a green (1D) histogram and not a 2D histogram. So here's your edited code, that (hopefully) does, what you want:
int main( int argc, char** argv )
{
Mat src,src1;
if( argc != 3 || !(src=imread(argv[1], 1)).data || !(src=imread(argv[2], 1)).data)
return -1;
// Quantize the green to 30 levels
int greenbins = 30;
int histSize[] = {greenbins};
// green varies from 0 to 255 (pure spectrum color)
float greenranges[] = { 0, 256 };
const float* ranges[] = { greenranges };
MatND hist, hist1, difference;
// we compute the histogram from the 2nd channel (green, index is 1)
int channels[] = {1};
calcHist( &src, 1, channels, Mat(), // do not use mask
hist, 1, histSize, ranges,
true, // the histogram is uniform
false );
calcHist( &src1, 1, channels, Mat(), // do not use mask
hist1, 1, histSize, ranges,
true, // the histogram is uniform
false );
double maxVal1=0;
double maxVal2 =0;
minMaxLoc(hist, 0, &maxVal1, 0, 0);
minMaxLoc(hist1, 0, &maxVal2, 0, 0);
double maxVal = max(maxVal1, maxVal2);
int scale = 10;
int width = 50;
Mat histImg = Mat::zeros(greenbins*scale, width, CV_8UC3);
Mat hist1Img = Mat::zeros(greenbins*scale, width, CV_8UC3);
Mat hist2Img = Mat::zeros(greenbins*scale, width, CV_8UC3);
double hist_diff =0;
hist_diff = compareHist(hist, hist1, CV_COMP_CORREL);
absdiff(hist, hist1, difference);
printf("\nHist Diff: %f\n", hist_diff);
for( int h = 0; h<greenbins; ++h)
{
float binVal = hist.at<float>(h);
int intensity = cvRound(binVal*255/maxVal);
rectangle( histImg, Point(0, h*scale),
Point(width, (h+1)*scale),
Scalar::all(intensity),
CV_FILLED );
}
for( int h = 0; h<greenbins; ++h)
{
float binVal = hist1.at<float>(h);
int intensity = cvRound(binVal*255/maxVal);
rectangle( hist1Img, Point(0, h*scale),
Point(width, (h+1)*scale),
Scalar::all(intensity),
CV_FILLED );
}
for(int h = 0; h < greenbins; ++h)
{
float binVal = difference.at<float>(h);
int intensity = cvRound(binVal*255/maxVal);
rectangle( hist2Img, Point(0, h*scale),
Point(width, (h+1)*scale),
Scalar::all(intensity),
CV_FILLED );
}
imshow( "Source", src );
imshow( "Source1", src1 );
imshow( "src1 green Histogram", histImg );
imshow( "src2 green Histogram", hist1Img );
imshow( "diff green Histogram", hist2Img );
waitKey();
}