lowest bin value histogram opencv - opencv

Is it possible to get the most left bin value after a peak as in the image.
I had tried the syntax below but it always return of coz the first bin (0,0).
cv::Point min_loc, max_loc;
cv::minMaxLoc(g_hist, &min, &max, &min_loc, &max_loc );
cout<<"\nMax Histo: "<<max;
cout<<"\nmax_loc: "<<max_loc;
l_hist: [0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;
0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;28.571428;400;166.96428;63.392857;0;33.92857;88.392853;18.75;3.5714285;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;
0;0;0;0;0;0;0;0;0;0]
the bin is 165. I need to get the number of the bin.

Related

What would be the best strategy to match color dominants between two pictures?

I need to match the color dominant between two different pictures, to make them as similar as possible.
For example,I would like to match the grayscale picture of the child below, to the sepia picture of the soldier and compensate for contrast and lighning.
So far, I am thinking to convert the pictures to YCrCb and match the contrast on the histogram of the Y channel and the color in the other channels.
I will have to do the same also between color pictures.
Any suggestions?
I have some ideas that should be of use - they kind of start in Photoshop and wander through Perl, ImageMagick and OpenCV. I am a big fan of the warm and beautiful tonalities achieved by photographers such as David Fokos and Michael Kenna and I worked out, many years back, how to replicate their toning.
First, load your image up in Photoshop, convert to black and white mode, and then back to RGB mode, add a Curves adjustment layer and a new layer with the original colour image. Your Layers window will look like this:
Now turn off all layers except the grey background, and use the Color Dropper to find and mark:
a quarter-tone pixel (i.e. value around 64 in the Info window)
a mid-tone pixel (i.e. around 128 in the Info window)
a three quarter-tone pixel (i.e. around 192 in the Info window)
Now turn the other layers back on and find what those three tones map to in RGB:
Now go in the Curves layer and adjust the Red, Green and Blue curves to match those values:
And if you then switch back to RGB, you can see all three curves on one diagram:
You now just need to save that Curve as a file with ACV extension and you can apply it to other images:
I got a bit bored doing that, so I wrote a Perl script that does exactly the same. You pass it a toned image as a filename, it finds the quarter, mid and three-quarter tones and then creates an Adobe Photoshop Curves file - an ACV file for you which you can then batch apply to other photos.
Here's the Perl:
#!/usr/bin/perl
use strict;
use warnings;
use Image::Magick;
use Data::Dumper;
my $Debug=1; # 1=print debug messages, 0=don't
my $NPOINTS=5; # Number of points in curve we create
# Read in image in first parameter
my $imagename=$ARGV[0];
my $orig=Image::Magick::->new;
my $x = $orig->Read($imagename);
warn "$x" if "$x";
my $width =$orig->Get('columns');
my $height=$orig->Get('rows');
my $depth=$orig->Get('depth');
print "DEBUG: ",$width,"x",$height,", depth: ",$depth,"\n" if $Debug;
# Access pixel cache
my #RGBpixels = $orig->GetPixels(map=>'RGB',height=>$height,width=>$width,normalize=>1);
my ($i,$j,$p);
my (#greypoint,#Rpoint,#Gpoint,#Bpoint);
for($p=0;$p<$NPOINTS;$p++){
my $greylevelsought=int(($p+1)*256/($NPOINTS+1));
my $nearestgrey=1000;
for(my $t=0;$t<$height*$width;$t++){
my $R = int(255*$RGBpixels[(3*$t)+0]);
my $G = int(255*$RGBpixels[(3*$t)+1]);
my $B = int(255*$RGBpixels[(3*$t)+2]);
my $this=int(0.21*$R + 0.72*$G +0.07*$B);
printf "Point: %d, Greysought: %d, this pixel: %d\n",$p,$greylevelsought,$this if $Debug>1;
if(abs($this-$greylevelsought)<abs($nearestgrey-$greylevelsought)){
$nearestgrey=$this;
$greypoint[$p]=$nearestgrey;
$Rpoint[$p]=$R;
$Gpoint[$p]=$G;
$Bpoint[$p]=$B;
}
}
printf "DEBUG: Point#: %d, sought grey: %d, nearest grey: %d\n",$p,$greylevelsought,$nearestgrey if $Debug;
}
# Work out name of the curve file = image basename + acv
my $curvefile=substr($imagename,0,rindex($imagename,'.')) . ".acv";
open(my $out,'>:raw',$curvefile) or die "Unable to open: $!";
print $out pack("s>",4); # Version=4
print $out pack("s>",4); # Number of curves in file = Master NULL curve + R + G + B
print $out pack("s>",2); # Master NULL curve with 2 points for all channels
print $out pack("s>",0 ),pack("s>",0 ); # 0 out, 0 in
print $out pack("s>",255),pack("s>",255); # 255 out, 255 in
print $out pack("s>",2+$NPOINTS); # Red curve
print $out pack("s>",0 ),pack("s>",0 ); # 0 out, 0 in
for($p=0;$p<$NPOINTS;$p++){
print $out pack("s>",$Rpoint[$p]),pack("s>",$greypoint[$p]);
}
print $out pack("s>",255),pack("s>",255); # 255 out, 255 in
print $out pack("s>",2+$NPOINTS); # Green curve
print $out pack("s>",0 ),pack("s>",0 ); # 0 out, 0 in
for($p=0;$p<$NPOINTS;$p++){
print $out pack("s>",$Gpoint[$p]),pack("s>",$greypoint[$p]);
}
print $out pack("s>",255),pack("s>",255); # 255 out, 255 in
print $out pack("s>",2+$NPOINTS); # Blue curve
print $out pack("s>",0 ),pack("s>",0 ); # 0 out, 0 in
for($p=0;$p<$NPOINTS;$p++){
print $out pack("s>",$Bpoint[$p]),pack("s>",$greypoint[$p]);
}
print $out pack("s>",255),pack("s>",255); # 255 out, 255 in
close($out);
If you want to do this in OpenCV, you could translate the first 70% of the script to OpenCV pretty simply - it is just 2 loops. Then you would have the quarter, mid and three-quarter tone points. You could use a curve-fitting program such as gnuplot (I have no idea of your skillset) to fit a curve to the points and then generate a lookup table for each of the 256 values 0-255, and apply that to your other images using cv::LUT() to replicate or clone the tone.

Histogram calculation in julia-lang

refer to julia-lang documentations :
hist(v[, n]) → e, counts
Compute the histogram of v, optionally using approximately n bins. The return values are a range e, which correspond to the edges of the bins, and counts containing the number of elements of v in each bin. Note: Julia does not ignore NaN values in the computation.
I choose a sample range of data
testdata=0:1:10;
then use hist function to calculate histogram for 1 to 5 bins
hist(testdata,1) # => (-10.0:10.0:10.0,[1,10])
hist(testdata,2) # => (-5.0:5.0:10.0,[1,5,5])
hist(testdata,3) # => (-5.0:5.0:10.0,[1,5,5])
hist(testdata,4) # => (-5.0:5.0:10.0,[1,5,5])
hist(testdata,5) # => (-2.0:2.0:10.0,[1,2,2,2,2,2])
as you see when I want 1 bin it calculates 2 bins, and when I want 2 bins it calculates 3.
why does this happen?
As the person who wrote the underlying function: the aim is to get bin widths that are "nice" in terms of a base-10 counting system (i.e. 10k, 2×10k, 5×10k). If you want more control you can also specify the exact bin edges.
The key word in the doc is approximate. You can check what hist is actually doing for yourself in Julia's base module here.
When you do hist(test,3), you're actually calling
hist(v::AbstractVector, n::Integer) = hist(v,histrange(v,n))
That is, in a first step the n argument is converted into a FloatRange by the histrange function, the code of which can be found here. As you can see, the calculation of these steps is not entirely straightforward, so you should play around with this function a bit to figure out how it is constructing the range that forms the basis of the histogram.

Understanding Template Matching in openCV

Just want to clear out my confusion. I've tested openCV template matching method to match some numbers. First I have this sequence of number 0 1 2 3 4 5 1 2 3 4 5 (after binarization probably the character width is different). How does template matching works to match number '1'? Does it;
slides through all the window until it found 2 matches (2 output), or
stop after it match the first '1', or
find the highest correlation between the two number '1' and choose either one.
Edited: As attached is the output. It only match one number '1' and not two '1'.
[Q] How can I detect two numbers '1' simultaneously?
I know it's an old question but here is an answer.
When you do MatchTemplate, it will output an grayscale image. After that, you will need to do a MinMax on it. Then, you can check if there is a result in the range you are looking for. In the example below, using EmguCV (a wrapper of OpenCV in C#), I draw a rectangle around the best find (index 0 of the minValues array) only if it's below 0.75 (you can adjust this threshold for your needs).
Here is the code:
Image<Gray, float> result = new Image<Gray, float>(new System.Drawing.Size(nWidth, nHeight));
result = image.CurrentImage.MatchTemplate(_imageTemplate.CurrentImage, Emgu.CV.CvEnum.TM_TYPE.CV_TM_SQDIFF_NORMED);
double[] minValues;
double[] maxValues;
System.Drawing.Point[] minLocations;
System.Drawing.Point[] maxLocations;
result.MinMax(out minValues, out maxValues, out minLocations, out maxLocations);
if (minValues[0] < 0.75)
{
Rectangle rect = new Rectangle(new Point(minLocations[0].X, minLocations[0].Y),
new Size(_imageTemplate.CurrentImage.Width, _imageTemplate.CurrentImage.Height));
image.CurrentImage.Draw(rect, new Bgr(0,0,255), 1);
}
else
{
//Nothing has been found
}
EDIT
Here is an example of the output:

counting bright pixels and summing them. Medical Image C++

Currently, I'm working on a project in medical engineering. I have a big image with several sub-images of the cell, so my first task is to divide the image.
I thought about the next thing:
Convert the image into binary
doing a projection of the brightness pixels into the x-axis so I can see where there are gaps between brightnesses values and then divide the image.
The problem comes when I try to reach the second part. My idea is using a vector as the projection and sum all the brightnesses values all along one column, so the position number 0 of the vector is the sum of all the brightnesses values that are in the first column of the image, the same until I reach the last column, so at the end I have the projection.
This is how I have tried:
void calculo(cv::Mat &result,cv::Mat &binary){ //result=the sum,binary the imag.
int i,j;
for (i=0;i<=binary.rows;i++){
for(j=0;j<=binary.cols;j++){
cv::Scalar intensity= binaria.at<uchar>(j,i);
result.at<uchar>(i,i)=result.at<uchar>(i,i)+intensity.val[0];
}
cv::Scalar intensity2= result.at<uchar>(i,i);
cout<< "content" "\n"<< intensity2.val[0] << endl;
}
}
When executing this code, I have a violation error. Another problem is that I cannot create a matrix with one unique row, so...I don't know what could I do.
Any ideas?! Thanks!
At the end, it does not work, I need to sum all the pixels in one COLUMN. I did:
cv::Mat suma(cv::Mat& matrix){
int i;
cv::Mat output(1,matrix.cols,CV_64F);
for (i=0;i<=matrix.cols;i++){
output.at<double>(0,i)=norm(matrix.col(i),1);
}
return output;
}
but It gave me a mistake:
Assertion failed (0 <= colRange.start && colRange.start <= colRange.end && colRange.end <= m.cols) in Mat, file /home/usuario/OpenCV-2.2.0/modules/core/src/matrix.cpp, line 276
I dont know, any idea would be helpful, anyway many thanks mevatron, you really left me in the way.
If you just want the sum of the binary image, you could simply take the L1-norm. Like so:
Mat binaryVectorSum(const Mat& binary)
{
Mat output(1, binary.rows, CV_64F);
for(int i = 0; i < binary.rows; i++)
{
output.at<double>(0, i) = norm(binary.row(i), NORM_L1);
}
return output;
}
I'm at work, so I can't test it out, but that should get you close.
EDIT : Got home. Tested it. It works. :) One caveat...this function works if your binary matrix is truly binary (i.e., 0's and 1's). You may need to scale the norm output with the maximum value if the binary matrix is say 0's and 255's.
EDIT : If you don't have using namespace cv; in your .cpp file, then you'll need to declare the namespace to use NORM_L1 like this cv::NORM_L1.
Have you considered transposing the matrix before you call the function? Like this:
sumCols = binaryVectorSum(binary.t());
vs.
sumRows = binaryVectorSum(binary);
EDIT : A bug with my code :)
I changed:
Mat output(1, binary.cols, CV_64F);
to
Mat output(1, binary.rows, CV_64F);
My test case was a square matrix, so that bug didn't get found...
Hope that is helpful!

OpenCV : How do I find the minimum element along a specific dimension?

I'm a new user to OpenCV. I'm using version 2.3.2 (from the SVN repository).
I have a specific 3-dimensional cv::Mat structure which is 288 x 384 x 10. This represents a 288 x 384 image and the other 10 channels represent a disparity value. I want to find the minimum element and its location. There is a minMaxElem function in OpenCV with it doesn't work with multi-dimensional arrays. Any idea how I can use the channel splitting functions in OpenCV to perform this?
You can use minMaxIdx function to find minimum/maximum on multidimensional array:
void minMaxIdx(InputArray src, double* minVal, double* maxVal,
int* minIdx=0, int* maxIdx=0, InputArray mask=noArray());
Non-zero minIdx and maxIdx should point to the arrays having enough length to store indexes for all dimensions (3 for 3-dimensional Mat).
minVal and maxVal are used to return single minimum/maximum value. They can be 0 if you don't need the values.

Resources