entropy for a gray image in opencv - c++

I need code to find entropy of an image.
for(int i=0;i<grey_image.rows;i++)
{
for(int j=1;j<grey_image.cols;j++)
{
//cout<<i<<" "<<j<<" "<<(int)grey_image.at<uchar>(i,j)<<endl;
int a=(int)grey_image.at<uchar>(i,j);
int b=(int)grey_image.at<uchar>(i,j-1);
int x=a-b;
if(x<0)
x=0-x;
probability_array[x]++;
//grey_image.at<uchar>(i,j) = 255;
}
}
//calculating probability
int n=rows*cols;
for(int i=0;i<256;i++)
{
probability_array[i]/=n;
//cout<<probability_array[i]<<endl;
}
// galeleo team formula
float entropy=0;
for(int i=0;i<256;i++)
{
if (probability_array[i]>0)
{
float x=probability_array[i]*log(probability_array[i]);
entropy+=x;
}
}
return 0-entropy;
Actually I am using this to dump in a programmable camera to measure entropy. Now I want to use it in windows system. I am getting entropy of a gray image as zero.Please help me out. Where did I go wrong.

Without knowing what image are you using, we cannot know if a zero entropy result is not the right answer (as suggested by #Xocoatzin).
Besides, your code can benefit from some of the latest OpenCV features 😊: Here is a working implementation using OpenCV histograms and matrix expressions:
if (frame.channels()==3) cvtColor(frame,frame,CV_BGR2GRAY);
/// Establish the number of bins
int histSize = 256;
/// Set the ranges ( for B,G,R) )
float range[] = { 0, 256 } ;
const float* histRange = { range };
bool uniform = true; bool accumulate = false;
/// Compute the histograms:
calcHist( &frame, 1, 0, Mat(), hist, 1, &histSize, &histRange, uniform, accumulate );
hist /= frame.total();
hist += 1e-4; //prevent 0
Mat logP;
cv::log(hist,logP);
float entropy = -1*sum(hist.mul(logP)).val[0];
cout << entropy << endl;

here is what i m using, hope it helps; https://github.com/samidalati/OpenCV-Entropy you can find couple of methods to calculate the entropy of colored and grayscaled images using OpenCV
float entropy(Mat seq, Size size, int index)
{
int cnt = 0;
float entr = 0;
float total_size = size.height * size.width; //total size of all symbols in an image
for(int i=0;i<index;i++)
{
float sym_occur = seq.at<float>(0, i); //the number of times a sybmol has occured
if(sym_occur>0) //log of zero goes to infinity
{
cnt++;
entr += (sym_occur/total_size)*(log2(total_size/sym_occur));
}
}
cout<<"cnt: "<<cnt<<endl;
return entr;
}
// myEntropy calculates relative occurrence of different symbols within given input sequence using histogram
Mat myEntropy(Mat seq, int histSize)
{
float range[] = { 0, 256 } ;
const float* histRange = { range };
bool uniform = true; bool accumulate = false;
Mat hist;
/// Compute the histograms:
calcHist( &seq, 1, 0, Mat(), hist, 1, &histSize, &histRange, uniform, accumulate );
return hist;
}

enter code here
//Calculate Entropy of 2D histogram
double Sum_prob_1k = 0, Sum_prob_kl = 0, Sum_prob_ln_1k = 0, Sum_prob_ln_kl = 0;
for (int k = start; k < end; k++)
{
Sum_prob_1k = 0; Sum_prob_kl = 0;
Sum_prob_ln_1k = 0; Sum_prob_ln_kl = 0;
//i=1 need to be start = 1
for (int i = 1; i < k; i++)
{
Sum_prob_1k += HiGreyN[i];
if (HiGreyN[i] != 0)
Sum_prob_ln_1k += (HiGreyN[i] * System.Math.Log(HiGreyN[i]));
}
for (int i = k; i < end; i++)
{
Sum_prob_kl += HiGreyN[i];
if (HiGreyN[i] != 0)
Sum_prob_ln_kl += (HiGreyN[i] * System.Math.Log(HiGreyN[i]));
}
//Final equation of entropy for each K
EiGrey[k] = System.Math.Log(Sum_prob_1k) + System.Math.Log(Sum_prob_kl) -
(Sum_prob_ln_1k / Sum_prob_1k) - (Sum_prob_ln_kl / Sum_prob_kl);
if (EiGrey[k] < 0)
EiGrey[k] = 0;
}
//End calculating 2D Entropy

Related

Histogram matching of two images with c++ and OpenCV 2.4.x

Since I found nothing about Histogram Matching in C++ and OpenCV 2.4 I ask here again a question.
All solutions I found for newer versions.
My code:
void histogramMatching(Mat & reference, Mat & input, Mat & result) {
const float HISMATCH = 0.001;
double min, max;
vector<Mat> reference_channels;
split(reference, reference_channels);
vector<Mat> input_channels;
split(input, input_channels);
int histSize = 256;
float range[] = { 0,256 };
const float* histrange = { range };
bool uniform = true;
for (int i = 0; i < 3; i++) {
Mat reference_histogram, input_histogram;
Mat reference_histogram_accum, input_histogram_accum;
calcHist(&input_channels[i], 1, 0, Mat(), input_histogram, 1, &histSize, &histrange, &uniform);
try {
calcHist(&reference_channels[i], 1, 0, Mat(), reference_histogram, 1, &histSize, &histrange, &uniform);
}
catch (int n) {
cout << "The first element is " << n << endl;
}
minMaxLoc(reference_histogram, &min, &max);
normalize(reference_histogram, reference_histogram, min / max, NORM_MINMAX);
minMaxLoc(input_histogram, &min, &max);
normalize(input_histogram, input_histogram, min / max, NORM_MINMAX);
reference_histogram.copyTo(reference_histogram_accum);
input_histogram.copyTo(input_histogram_accum);
float* src_cdf_data = input_histogram_accum.ptr<float>();
float* dst_cdf_data = reference_histogram_accum.ptr<float>();
for (int j = 1; j < 256; j++) {
src_cdf_data[j] += src_cdf_data[j - 1];
dst_cdf_data[j] += dst_cdf_data[j - 1];
}
minMaxLoc(reference_histogram_accum, &min, &max);
normalize(reference_histogram_accum, reference_histogram_accum, min / max, 1.0, NORM_MINMAX);
minMaxLoc(input_histogram_accum, &min, &max);
normalize(input_histogram_accum, input_histogram_accum, min / max, 1.0, NORM_MINMAX);
//BEGIN Matching
Mat lut(1, 256, CV_8UC1);
uchar* M = lut.ptr<uchar>();
uchar last = 0;
for (int j = 0; j < input_histogram_accum.rows; j++) {
float F1 = dst_cdf_data[j];
int i = 0;
for (uchar k = last; k < reference_histogram_accum.rows; k++) {
i++;
float F2 = src_cdf_data[k];
if (abs(F2 - F1) < HISMATCH || F2 > F1) {
M[j] = k;
last = k;
break;
}
}
}
LUT(input_channels[i], lut, input_channels[i]);
}
merge(input_channels, result);
}
public:int execute() {
Mat input = imread("input.jpg", IMREAD_COLOR);
if (input.empty()) {
cout << "Image is empty" << endl;
return -1;
}
Mat reference = imread("fuchs.jpg", IMREAD_COLOR);
if (reference.empty()) {
cout << "Reference Image is empty" << endl;
return -1;
}
Mat result = input.clone();
namedWindow("Reference", WINDOW_AUTOSIZE);
namedWindow("Input", WINDOW_AUTOSIZE);
namedWindow("Result", WINDOW_AUTOSIZE);
imshow("Reference", reference);
imshow("Input", input);
histogramMatching(reference, input, result);
imshow("Result", result);
waitKey(0);
return 0;
}
All works, but the loop which begins with "for (int j = 0; j < input_histogram_accum.rows; j++) {", get no response and i waited for more than 6 hours and i think it doesn't work. My input image is 500kb and my fuchs.jpg is 180 kb.
Has anybody a solution for histogram matching with C++ and OpenCV 2.4.x?

Color to grayscale conversion

Im using a C++ openCV program for first principles Algorithm development for HDL(Verilog) image object detection. I've finally managed to get HDL version up to the point of canny detection. In order to validate the two, both need to have identical output. I have found their are subtle differences that I thing are being contributed to by the openCV imread colour to grayscale conversion biasing green. The smoothed image is overall brighter in the openCV C++ method. From looking at the rgb2gray method it appears openCV used a bias ie (RX+GY+B*Z)/3 while in HDL I have been using (R+G+B)/3 as I require it to complete Gaussian, Sobel and Canny filters. Human visualisation is secondary and multiplication by a non-int is undesirable.
Is there a standard linear grayscale conversion for conversion or a means to override the existing method?
...
int main()
{
int thold = 15;
clock_t start;
double duration;
const int sobelX[3][3] = { {-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1} }; //Where origionally floats in python
const int sobelY[3][3] = { {-1, -2, -1}, {0, 0, 0}, {1, 2, 1} }; //Where origionally floats in python
const int kernel[5][5] = { {1,6,12,6,1},
{6,42,79,42,6},
{12,79,148,79,12},
{6,42,79,42,6},
{1,6,12,6,1} };// 1/732
// Above normalised kernal for smoothing, see origional python script for method
start = std::clock();
int height, width, intPixel, tSx, tSy, tS, dirE, dirEE, maxDir, curPoint, contDirection, cannyImgPix, nd, tl, tm, tr, mr, br, bm, bl, ml = 0;
int contNum = 128;
int contPixCount = 0;
int curContNum = 0;
int contPlace = 0;
int oldContPlace = 0;
int g = 0;
bool maxPoint;
struct pixel {
int number;
int h;
int w;
};
std::vector<pixel> contourList;
//double floatPixel = 0.0;
int kernalCumulator = 0;
const int mp = 3;
// Scalar color(0, 0, 255);
// duration = ((clock()) - start) / (double)CLOCKS_PER_SEC;
// start = clock();
// cout << "Start image in" << duration << '\n';
// Mat dst;
Mat rawImg = imread("C:\\Users\\&&&\\Documents\\pycode\\paddedGS.png",0);
printf("%d",rawImg.type());
// Mat rawImg = imread("C:\\Users\\&&&\\Documents\\openCV_Master\\openCVexample\\openCVexample\\brace200.jpg ", 0);
height = rawImg.rows;
width = rawImg.cols;
cout << "Height of image " << height << '\n';
cout << "Width of image " << width << '\n';
Mat filteredImg = Mat::zeros(height, width, CV_8U);
printf("%d", filteredImg.type());
Mat sobelImg = Mat::zeros(height, width, CV_8U);
Mat directionImg = Mat::zeros(height, width, CV_8U);
Mat cannyImg = Mat::zeros(height, width, CV_8U);
Mat contourImg = Mat::zeros(height, width, CV_16U);
// rawImg.convertTo(rawImg, CV_8UC1);
duration = ((clock()) - start) / (double)CLOCKS_PER_SEC;
start = clock();
cout << "Start image in" << duration << '\n';
// Loop to threshold already grayscaled image
/*
for (int h = 0; h < (height); h++)
{
for (int w = 0; w < (width); w++)
{
g = (int)rawImg.at<uchar>(h, w,0);
cout << g << "g";
g+= (int)rawImg.at<uchar>(h, w, 1);
cout << g << "g";
g+= (int)rawImg.at<uchar>(h, w, 2);
cout << g << "g";
g = g/3;
rawGImg.at<uchar>(h,w) = g;
}
}
*/
// imshow("thresholded Image", rawImg);
// waitKey();
// Loop to smooth using Gausian 5 x 5 kernal
// imshow("raw Image", rawImg);
for (int h = 3; h < (height - 3); h++)
{
for (int w = 3; w < (width - 3); w++)
{
if (rawImg.at<uchar>(h, w) >=6 )//Thresholding included
{
for (int xk = 0; xk < 5; xk++)
{
for (int yk = 0; yk < 5; yk++)
{
intPixel = rawImg.at<uchar>((h + (xk - mp)), (w + (yk - mp)));
kernalCumulator += intPixel*(kernel[xk][yk]);//Mutiplier required as rounding is making number go above 255, better solution?
}
}
}
else
kernalCumulator = 0;
kernalCumulator = kernalCumulator / 732;
if (kernalCumulator < 0 || kernalCumulator > 255)
{
// cout << "kernal Value: " << kernalCumulator;
// cout << " intPixel:" << intPixel << '\n';
}
filteredImg.at<uchar>(h, w) = (uchar)kernalCumulator;
kernalCumulator = 0;
}
}
Our vision does not perceive linearly the brightness, so it makes sense for usual applications to use some sort of transformation that tries to mimic the human perception.
For your application, you have 2 options: either use a similar transformation in HDL (which might not be easy or desired), or make a custom rgb to grayscale for OpenCV which uses the same transformation you use.
A short snippet (more like pseudocode, you'll have to figure out the details) for this would be something like:
cv::Mat linearRgbToGray(const cv::Mat &color) {
cv::Mat gray(color.size(), CV_8UC1);
for (int i = 0; i < color.rows; i++)
for (int j = 0; j < color.cols; j++)
gray.at(i, j) = (color.at(i, j)[0] + color.at(i, j)[1] + color.at(i, j)[2]) / 3;
}
As per Paul92's advice above
cv::Mat linearRgbToGray(const cv::Mat &color) {
cv::Mat gray(color.size(), CV_8UC1);
for (int i = 0; i < color.rows; i++)
for (int j = 0; j < color.cols; j++)
gray.at<uchar>(i, j) = ((color.at<cv::Vec3b>(i, j)[0] + color.at<cv::Vec3b>(i, j)[1] + color.at<cv::Vec3b>(i, j)[2]) / 3);
return gray;
}
The above code worked and overcame out of bounds errors I experienced earlier. Thank you, Rob.

Max entropy thresholding using OpenCV [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I'm trying to convert the code for using the maximum entropy thresholding from this matlab code:
%**************************************************************************
%**************************************************************************
%
% maxentropie is a function for thresholding using Maximum Entropy
%
%
% input = I ==> Image in gray level
% output =
% I1 ==> binary image
% threshold ==> the threshold choosen by maxentropie
%
% F.Gargouri
%
%
%**************************************************************************
%**************************************************************************
function [threshold I1]=maxentropie(I)
[n,m]=size(I);
h=imhist(I);
%normalize the histogram ==> hn(k)=h(k)/(n*m) ==> k in [1 256]
hn=h/(n*m);
%Cumulative distribution function
c(1) = hn(1);
for l=2:256
c(l)=c(l-1)+hn(l);
end
hl = zeros(1,256);
hh = zeros(1,256);
for t=1:256
%low range entropy
cl=double(c(t));
if cl>0
for i=1:t
if hn(i)>0
hl(t) = hl(t)- (hn(i)/cl)*log(hn(i)/cl);
end
end
end
%high range entropy
ch=double(1.0-cl); %constraint cl+ch=1
if ch>0
for i=t+1:256
if hn(i)>0
hh(t) = hh(t)- (hn(i)/ch)*log(hn(i)/ch);
end
end
end
end
% choose best threshold
h_max =hl(1)+hh(1)
threshold = 0;
entropie(1)=h_max;
for t=2:256
entropie(t)=hl(t)+hh(t);
if entropie(t)>h_max
h_max=entropie(t);
threshold=t-1;
end
end
% Display
I1 = zeros(size(I));
I1(I<threshold) = 0;
I1(I>threshold) = 255;
%imshow(I1)
end
The problem is that I'm getting floating point excpetion error in the code, and I cannot understand why
This is my implementation:
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <math.h>
using namespace cv;
using namespace std;
int main(){
cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
cout.precision(9);
Mat old_image=imread("2.png",CV_LOAD_IMAGE_GRAYSCALE);
double minval, maxval;
minMaxLoc(old_image,&minval, &maxval);
cout<<minval<<" "<<maxval<<endl;
Mat image;
old_image.convertTo(image, CV_8UC1, 255.0/(maxval-minval), -minval*255.0/(maxval-minval));
minMaxLoc(image,&minval, &maxval);
cout<<minval<<" "<<maxval;
int k=0;
imshow("im",image);
waitKey(0);
for(int y=0; y<image.rows;y++){
for(int x=0; x<image.cols;x++){
if((int) image.at<uchar>(y,x)==0){
k++;
}
}
}
cout<<k<<endl<<endl;
int i, l, j, t;
int histSize = 256;
float range[] = { 0, 255 };
const float *ranges[] = { range };
Mat hist, histogram, c, ctmp, hl, hh, hhtmp, entropy;
calcHist( &image, 1, 0, Mat(), hist, 1, &histSize, ranges, true, false );
for( int h = 1; h < histSize; h++){
histogram.push_back(hist.at<float>(h,0));
cout<<histogram.rows<<endl;
cout<<histogram.row(h-1)<<endl;
cout<<hist.row(h)<<endl;
}
histogram=histogram/(image.rows*image.cols-hist.at<float>(0,0));
//cumulative distribution function
float cl,ch;
ctmp.push_back(histogram.row(0));
c.push_back(histogram.row(0));
cout<<c.row(0)<<endl;
for(l=1;l<255;l++){
c.push_back(ctmp.at<float>(0)+histogram.at<float>(l));
ctmp.push_back(c.row(l));
cout<<c.at<float>(l)<<endl;
//c.row(l)=c.row(l-1)+histogram.row(l);
}
Mat hltmp= Mat::zeros(1,256,CV_8U);
// THE PROBLEM IS IN THIS TWO FOR CYCLES
for(t=0;t<255;t++){
//low range entropy
cl=c.at<float>(t);
if(cl>0){
for(i=0;i<=t;i++){
if(histogram.at<float>(t)>0){
printf("here\n");
hl.push_back(hltmp.at<float>(0)-(histogram.at<float> (i)/cl)*log(histogram.at<float>(i)/cl));
printf("here\n");
cout<<hl.at<float>(i);
printf("here\n");
hltmp.push_back(hl.row(t));
printf("here\n");
}
}
}
printf("here\n");
//high range entropy
ch=1.0-cl;
if(ch>0){
for(i=t+1;i<255;i++){
if(histogram.at<float>(i)>0){
hh.push_back(hh.at<float>(t)-(histogram.at<float> (i)/ch)*log(histogram.at<float>(i)/ch));
}
}
}
}
//choose the best threshold
float h_max=hl.at<float>(0,0)+hh.at<float>(0,0);
float threshold=0;
entropy.at<float>(0,0)=h_max;
for(t=1;t<255;t++){
entropy.at<float>(t)=hl.at<float>(t)+hh.at<float>(t);
if(entropy.at<float>(t)>h_max){
h_max=entropy.at<float>(t);
threshold=t-1;
}
cout<<threshold<<endl;
}
//display
Mat I1= Mat::zeros(image.rows,image.cols,CV_8UC1);
for(int y=0; y<image.rows;y++){
for(int x=0; x<image.cols;x++){
if((int) image.at<uchar>(y,x)<threshold){
I1.at<uchar>(y,x)=0;
}
else{
I1.at<uchar>(y,x)=255;
}
}
}
imshow("image",I1);
waitKey(0);*/
return 0;
}
Your problem is that you're reading float elements from a CV_8U (aka uchar) Mat.
Mat hltmp = Mat::zeros(1, 256, CV_8U);
...
hltmp.at<float>(0)
You should learn how to use a debugger, and you'll find out these problems very soon.
Since you over-complicated things in your implementation, made some errors, and the code is cluttered from debug prints, I propose the one below instead of punctually correct your (not many, but mainly conceptual) errors. You can see that, if written properly, there is almost a 1:1 conversion from Matlab to OpenCV.
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
uchar maxentropie(const Mat1b& src, Mat1b& dst)
{
// Histogram
Mat1d hist(1, 256, 0.0);
for (int r=0; r<src.rows; ++r)
for (int c=0; c<src.cols; ++c)
hist(src(r,c))++;
// Normalize
hist /= double(src.rows * src.cols);
// Cumulative histogram
Mat1d cumhist(1, 256, 0.0);
float sum = 0;
for (int i = 0; i < 256; ++i)
{
sum += hist(i);
cumhist(i) = sum;
}
Mat1d hl(1, 256, 0.0);
Mat1d hh(1, 256, 0.0);
for (int t = 0; t < 256; ++t)
{
// low range entropy
double cl = cumhist(t);
if (cl > 0)
{
for (int i = 0; i <= t; ++i)
{
if (hist(i) > 0)
{
hl(t) = hl(t) - (hist(i) / cl) * log(hist(i) / cl);
}
}
}
// high range entropy
double ch = 1.0 - cl; // constraint cl + ch = 1
if (ch > 0)
{
for (int i = t+1; i < 256; ++i)
{
if (hist(i) > 0)
{
hh(t) = hh(t) - (hist(i) / ch) * log(hist(i) / ch);
}
}
}
}
// choose best threshold
Mat1d entropie(1, 256, 0.0);
double h_max = hl(0) + hh(0);
uchar threshold = 0;
entropie(0) = h_max;
for (int t = 1; t < 256; ++t)
{
entropie(t) = hl(t) + hh(t);
if (entropie(t) > h_max)
{
h_max = entropie(t);
threshold = uchar(t);
}
}
// Create output image
dst = src > threshold;
return threshold;
}
int main()
{
Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);
Mat1b res;
uchar th = maxentropie(img, res);
imshow("Original", img);
imshow("Result", res);
waitKey();
return 0;
}

CImg: Image binarization result fails

So, the problem in my following code is that the result of the image binarization becomes too dark. (There was even an example image I have whose binary image becomes wholly black.)
I have been searching any mistake in my code for a very long time, and have found none that seemingly looks problematic to me.
Below is the image I want to binarize:
Image before binarized - in my code is named: "hildebrantmed.bmp"
Below is the resulting binary image:
Image after binarized
Before I show you my source code, here are the 'rules' in the image binarization (since this is an assignment I recently got):
I am not allowed to use any other libraries than CImg.
The programming language to use is C/C++. Not any other else.
Normally, the Otsu's method is the choice. However, I may be allowed to use other algorithms if it is better.
Lastly, here is my source code:
#include <iostream>
#include <CImg.h>
using namespace std;
using namespace cimg_library;
/**
* Generate histogram of the grayscale image
*/
int * generate_histogram(CImg<unsigned char> img)
{
int histogram[256];
// initialize default values for histogram
for (int i = 0; i < 256; i++)
{
histogram[i] = 0;
}
// increment intensity for histogram
for (int i = 0; i < img.height(); i++)
{
for (int j = 0; j < img.width(); j++)
{
int gray_value = img(j, i, 0, 0);
histogram[gray_value]++;
}
}
return histogram;
}
/**
* Find threshold value from the grayscale image's histogram
*/
int otsu_threshold(CImg<unsigned char> img)
{
int * histogram = generate_histogram(img); // image histogram
int total = img.width() * img.height(); // total pixels
double sum = 0;
int i;
for (i = 0; i < 256; i++)
{
sum += i * histogram[i];
}
double sumB = 0;
int wB = 0;
int wF = 0;
double var_max = 0;
int threshold = 0;
for (i = 0; i < 256; i++)
{
wB += histogram[i];
if (wB == 0) continue;
wF = total - wB;
if (wF == 0) continue;
sumB += (double)(i * histogram[i]);
double mB = sumB / wB;
double mF = (sum - sumB) / wF;
double var_between = (double)wB * (double)wF * (mB - mF) * (mB - mF);
if (var_between > var_max)
{
var_max = var_between;
threshold = i;
}
}
return threshold;
}
/**
* Main function
*/
int main(int argc, char * argv[])
{
// retrieve image from its path
CImg<unsigned char> img("hildebrantmed.bmp");
const int width = img.width();
const int height = img.height();
// initialize a new image for img's grayscale
CImg<unsigned char> gray_img(width, height, 1, 1, 0);
// from RGB divided into three separate channels
CImg<unsigned char> imgR(width, height, 1, 3, 0);
CImg<unsigned char> imgG(width, height, 1, 3, 0);
CImg<unsigned char> imgB(width, height, 1, 3, 0);
// for all (x, y) pixels in image
cimg_forXY(img, x, y)
{
imgR(x, y, 0, 0) = img(x, y, 0, 0),
imgG(x, y, 0, 1) = img(x, y, 0, 1),
imgB(x, y, 0, 2) = img(x, y, 0, 2);
// separate the channels
int R = (int)img(x, y, 0, 0);
int G = (int)img(x, y, 0, 1);
int B = (int)img(x, y, 0, 2);
// obtain gray value from different weights of RGB channels
int gray_value = (int)(0.299 * R + 0.587 * G + 0.114 * B);
gray_img(x, y, 0, 0) = gray_value;
}
// find threshold of grayscale image
int threshold = otsu_threshold(gray_img);
// initialize a binary image version of img
CImg<unsigned char> binary_img(width, height, 1, 1, 0);
// for every (x, y) pixel in gray_img
cimg_forXY(img, x, y)
{
int gray_value = gray_img(x, y, 0, 0);
// COMPARE gray_value with threshold
int binary_value;
// gray_value > threshold: 255 (white)
if (gray_value > threshold) binary_value = 255;
// gray_value < threshold: 0 (black)
else binary_value = 0;
// assign binary_value to each of binary_img's pixels
binary_img(x, y, 0, 0) = binary_value;
}
// display the images
CImgDisplay src_disp(img, "Source image");
CImgDisplay gray_disp(gray_img, "Grayscale image");
CImgDisplay binary_disp(binary_img, "Binary image");
while (!src_disp.is_closed() && !gray_disp.is_closed() && !binary_disp.is_closed())
{
src_disp.wait();
gray_disp.wait();
}
return 0;
}
If you find that another algorithm would work better, please provide with the algorithm and source code in your answer. Thanks for your attention.
First error: you're trying to return an array's pointer which actually gets destroyed as soon as the generate_histogram function ends.
To make it work properly, you should supply the pointer to an array from the calling function, something like:
{
//[....]
int histogram[256];
generate_histogram(img, histogram);
//[....]
}
int * generate_histogram(CImg<unsigned char> img, int* arHistogram)
{
//[....]
}

corruption of the heap

I have one function dealing with image. In that function, i am trying to find several particular ellipses. The code is working if i call it individually in a separate project, but in the whole project, it crashed when it returns.
I used many vectors in the processing to store some information during the process.
The error information:
Windows has triggered a breakpoint in KinectBridgeWithOpenCVBasics-D2D.exe.
This may be due to a corruption of the heap, which indicates a bug in KinectBridgeWithOpenCVBasics-D2D.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while KinectBridgeWithOpenCVBasics-D2D.exe has focus.
The output window may have more diagnostic information.
could any one tell me where is wrong to cause this crash. More weird is it is working in the separate project.
The code is a little long, but it is really noting, just looking for several particular ellipses with some pattern.
Thank you.
int FindNao(Mat* pImg, double* x, double* y)
{
// Fail if pointer is invalid
if (!pImg)
{
return 2;
}
// Fail if Mat contains no data
if (pImg->empty())
{
return 3;
}
//*x = 0; *y = 0;
Mat localMat = *pImg; // save a local copy of the image
cvtColor(~localMat, localMat, CV_BGR2GRAY); // Convert to gray image
threshold(localMat, localMat, 165, 255, THRESH_BINARY); // Convert into black-white image
Mat elementOpen = getStructuringElement(MORPH_ELLIPSE, Size(5,5), Point(-1,-1));
morphologyEx(localMat, localMat, MORPH_OPEN, elementOpen, Point(-1,-1), 1);
// Find all the contours in the blak-white image
vector<vector<Point>> contours;
findContours(localMat.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
localMat.release();
// Calculate the area of each contour
vector<double> areas; int num = contours.size();
/* If no contours are found, return S_OK */
if(num < 1)
return 1;
for(int i = 0; i < num; i++)
{
areas.push_back(contourArea(contours[i]));
}
// First round of selection
// The area is small, and they are like a ellipse and around the middle in X direction and at the upper part of the image
vector<RotatedRect> selected_ellipses; // store the fitted ellipse fitted to the potential contour
vector<double> selected_areas; // store the contour area of the potential contour
int imgX = localMat.cols; int imgY = localMat.rows; // get the demension of the image
for(int i=0; i < num - 1; i++)
{
if(areas[i] < 350 && areas[i] > 10)
{
// fit an ellipse
RotatedRect ellipse1 = fitEllipse(Mat(contours[i]));
// it is a reasonable ellipse, and the area should be close to the
double length1 = ellipse1.size.height;
double length2 = ellipse1.size.width;
if( abs(1 - length1/length2) <= 0.8 &&
abs(1 - areas[i] / (CV_PI * length1 * length2 / 4) ) <= 0.2 )
{
selected_ellipses.push_back(ellipse1);
selected_areas.push_back(areas[i]);
}
}
}
/************ Second round of selection **************/
// Calculate each ellipse's dimension
vector<double> diff_dimension;
vector<double> ave_dimention;
/* If no contours are found, return S_OK */
if(selected_ellipses.size() < 1)
return 1;
for(int i = 0; i < selected_ellipses.size(); i++)
{
double difference = abs(1 - selected_ellipses[i].size.height / selected_ellipses[i].size.width);
diff_dimension.push_back(difference);
double average = (selected_ellipses[i].size.height + selected_ellipses[i].size.width) / 2;
ave_dimention.push_back(average);
}
vector<vector<int>> eyematches;
vector<vector<int>> cammatches;
// go over all the ellipses to find the matches with close area and dimension.
for(int i = 0; i < selected_ellipses.size() - 1; i++)
{
for(int j = i+1; j < selected_ellipses.size(); j++)
{
// looking for the eyes
if(diff_dimension[i] < 0.05 && diff_dimension[j] < 0.05)
{
double diff_area = abs( 1 - selected_areas[i] / selected_areas[j] );
if (diff_area < 0.05)
{
double diff_y = abs(selected_ellipses[i].center.y - selected_ellipses[j].center.y);
if(diff_y < 10)
{
vector<int> match1;
match1.push_back(i); match1.push_back(j);
eyematches.push_back(match1);
}
}
}
// looking for the cameras
double diff_x = abs(selected_ellipses[i].center.x - selected_ellipses[j].center.x);
if (diff_x < 10)
{
vector<int> match2;
match2.push_back(i); match2.push_back(j);
cammatches.push_back(match2);
}
}
}
/* Last check */
int num_eyes = eyematches.size();
int num_cams = cammatches.size();
if(num_eyes == 0 || num_cams == 0)
return 1;
// Calculate the vector between two eyes and the center
vector<Point> vector_eyes; vector<Point> center_eyes;
vector<vector<int>>::iterator ite = eyematches.begin();
while(ite < eyematches.end())
{
Point point;
point.x = selected_ellipses[(*ite)[0]].center.x - selected_ellipses[(*ite)[1]].center.x;
point.y = selected_ellipses[(*ite)[0]].center.y - selected_ellipses[(*ite)[1]].center.y;
vector_eyes.push_back(point);
point.x = (selected_ellipses[(*ite)[0]].center.x + selected_ellipses[(*ite)[1]].center.x)/2;
point.y = (selected_ellipses[(*ite)[0]].center.y + selected_ellipses[(*ite)[1]].center.y)/2;
center_eyes.push_back(point);
ite++;
}
// Calculate the vector between two cameras and the center
vector<Point> vector_cams; vector<Point> center_cams;
ite = cammatches.begin();
while(ite < cammatches.end())
{
Point point;
point.x = selected_ellipses[(*ite)[0]].center.x - selected_ellipses[(*ite)[1]].center.x;
point.y = selected_ellipses[(*ite)[0]].center.y - selected_ellipses[(*ite)[1]].center.y;
vector_cams.push_back(point);
point.x = (selected_ellipses[(*ite)[0]].center.x + selected_ellipses[(*ite)[1]].center.x)/2;
point.y = (selected_ellipses[(*ite)[0]].center.y + selected_ellipses[(*ite)[1]].center.y)/2;
center_cams.push_back(point);
ite++;
}
// Match the eyes and cameras, by calculating the center distances and intersection angle
vector<vector<int>> matches_eye_cam;
vector<vector<double>> matches_parameters;
for(int i = 0; i < num_eyes; i++)
{
for(int j = 0; j < num_cams; j++)
{
vector<int> temp1;
vector<double> temp2;
// calculate the distances
double distance = sqrt( double( (center_eyes[i].x - center_cams[j].x)^2 + (center_eyes[i].y - center_cams[j].y)^2 ) );
// calculate the cosine intersection angle
double cosAngle = vector_eyes[i].x * vector_cams[j].x + vector_eyes[i].y * vector_cams[j].y;
// store everything
temp1.push_back(i); temp1.push_back(j);
temp2.push_back(distance); temp2.push_back(cosAngle);
matches_eye_cam.push_back(temp1);
matches_parameters.push_back(temp2);
}
}
// go over to find the minimum
int min_dis = 0; int min_angle = 0;
vector<vector<double>>::iterator ite_para = matches_parameters.begin();
/* If no contours are found, return S_OK */
if(matches_parameters.size() < 1)
return 1;
for(int i = 1; i < matches_parameters.size(); i++)
{
if( (*(ite_para+min_dis))[0] > (*(ite_para+i))[0] )
min_dis = i;
if( (*(ite_para+min_angle))[1] > (*(ite_para+i))[1] )
min_angle = i;
}
// get the best match of eyes and cameras 's index
int eyes_index, cams_index;
vector<vector<int>>::iterator ite_match_eye_cam = matches_eye_cam.begin();
if(min_dis == min_angle)
{
// perfect match
eyes_index = (*(ite_match_eye_cam + min_dis))[0];
cams_index = (*(ite_match_eye_cam + min_dis))[1];
}
else
{
// tried to fuse them and find a better sulotion, but didnot work out, so
// go with the min_dis
eyes_index = (*(ite_match_eye_cam + min_dis))[0];
cams_index = (*(ite_match_eye_cam + min_dis))[1];
}
vector<vector<int>>::iterator ite_eyes = eyematches.begin();
vector<vector<int>>::iterator ite_cams = cammatches.begin();
// draw the eyes
ellipse(*pImg, selected_ellipses[(*(ite_eyes+eyes_index))[0]], Scalar(0, 255, 255), 2, 8);
ellipse(*pImg, selected_ellipses[(*(ite_eyes+eyes_index))[1]], Scalar(0, 255, 255), 2, 8);
// draw the camera
ellipse(*pImg, selected_ellipses[(*(ite_cams+cams_index))[0]], Scalar(0, 255, 0), 2, 8);
ellipse(*pImg, selected_ellipses[(*(ite_cams+cams_index))[1]], Scalar(0, 255, 0), 2, 8);
imshow("show", *pImg);
// find the upper camera
int m1 = (*(ite_cams+cams_index))[0];
int m2 = (*(ite_cams+cams_index))[1];
int upper;
if(selected_ellipses[m1].center.y < selected_ellipses[m2].center.y)
upper = m1;
else
upper = m2;
*x = selected_ellipses[upper].center.x;
*y = selected_ellipses[upper].center.y;
return 1;
}
int main()
{
Mat imO = imread("Capture.PNG");
double x, y;
FindNao(&imO, &x, &y);
cout<<x<<" "<<y<<endl;
cvWaitKey(0);
}