Is there a way in Java or OpenCv ; preferably Java, that i can have an HSV histogram give RGB image.
I tried exploring JAI but it creates histogram for RGB image.
Thanks
Harshit
firs use cv::cvtColor to convert RGB to HSV
then use cv::calcHist to compute the histogram
Here is the pseudocode for a simple RGB to HSV converter. It will give a H of UNDEFINED if the color is a shade of gray, otherwise H is between 0 and 6.
x = min(R, G, B);
V = max(R, G, B);
if (V == x) {
H = UNDEFINED
S = 0
}
else {
if( R == x ) {
f = G - B;
i = 3;
} else if( G == x ) {
f = B - R;
i = 5;
} else {
f = R - G;
i = 1;
}
H = i - f /(V - x);
S = (V - x)/V;
}
Now you can either convert all your pixels and bin them to construct your HSV histogram, or you can convert each bin of your RGB histogram to an HSV bin.
You can use the "JavaCV" library to access OpenCV functions directly from Java:
http://code.google.com/p/javacv/
Then you can use my code for RGB to HSV that is better than OpenCV's cvConvert function:
http://www.shervinemami.co.cc/colorConversion.html
Cheers,
Shervin Emami.
Here is a code to do this:
// Assume SourceImage is a Bitmap ARGB_8888
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap refImage = BitmapFactory.decodeFile(mBaseDir + "some_reference.jpg", options);
Mat hsvRef = new Mat();
Mat hsvSource = new Mat();
Mat srcRef = new Mat(refImage.getHeight(), refImage.getWidth(), CvType.CV_8U, new Scalar(4));
Utils.bitmapToMat(refImage, srcRef);
Mat srcSource = new Mat(SourceImage.getHeight(), SourceImage.getWidth(), CvType.CV_8U, new Scalar(4));
Utils.bitmapToMat(SourceImage, srcSource);
/// Convert to HSV
Imgproc.cvtColor(srcRef, hsvRef, Imgproc.COLOR_BGR2HSV);
Imgproc.cvtColor(srcSource, hsvSource, Imgproc.COLOR_BGR2HSV);
/// Using 50 bins for hue and 60 for saturation
int hBins = 50;
int sBins = 60;
MatOfInt histSize = new MatOfInt( hBins, sBins);
// hue varies from 0 to 179, saturation from 0 to 255
MatOfFloat ranges = new MatOfFloat( 0f,180f,0f,256f );
// we compute the histogram from the 0-th and 1-st channels
MatOfInt channels = new MatOfInt(0, 1);
Mat histRef = new Mat();
Mat histSource = new Mat();
ArrayList<Mat> histImages=new ArrayList<Mat>();
histImages.add(hsvRef);
Imgproc.calcHist(histImages,
channels,
new Mat(),
histRef,
histSize,
ranges,
false);
Core.normalize(histRef,
histRef,
0,
1,
Core.NORM_MINMAX,
-1,
new Mat());
histImages=new ArrayList<Mat>();
histImages.add(hsvSource);
Imgproc.calcHist(histImages,
channels,
new Mat(),
histSource,
histSize,
ranges,
false);
Core.normalize(histSource,
histSource,
0,
1,
Core.NORM_MINMAX,
-1,
new Mat());
double resp1 = Imgproc.compareHist(histRef, histSource, 0);
double resp2 = Imgproc.compareHist(histRef, histSource, 1);
double resp3 = Imgproc.compareHist(histRef, histSource, 2);
double resp4 = Imgproc.compareHist(histRef, histSource, 3);
First, you have to convert image to HSV using cv::cvtColor to convert RGB image into HSV image and then, you can use cv::calcHist to compute the HSV histogram.
Related
When i apply houghCircle to my image it always detect the inner circle, i spent much time tuning the parameters but the result always the same.
My procedure is convert image into HSV color space then Threshold on a red color to get a binary image then applying houghCircle.
My Image
After Hough Circle
Code
Mat hsv = new Mat();
Imgproc.cvtColor(bgr, hsv, Imgproc.COLOR_BGR2HSV); //BGR to HSV
Mat mask1 = new Mat();
Mat mask2 = new Mat();
Core.inRange(hsv, new Scalar(0, 100, 100), new Scalar(10, 255, 255), mask1);
Core.inRange(hsv, new Scalar(160, 100, 100), new Scalar(179, 255, 255), mask2);
Mat hsvThres = new Mat();
Core.bitwise_or(mask1, mask2, hsvThres);
//
Mat circles = new Mat();
int iCannyUpperThreshold = 1; //100
int iMinRadius = -1; //20 //90
int iMaxRadius = -1; //400 //150-1000
int iAccumulator = 1;//300
Imgproc.HoughCircles(hsvThres, circles, Imgproc.CV_HOUGH_GRADIENT, //2
1.0, hsvThres.rows() , iCannyUpperThreshold, iAccumulator, iMinRadius, iMaxRadius);
if (circles.cols() > 0)
for (int x = 0; x < circles.cols(); x++)
{
double vCircle[] = circles.get(0,x);
if (vCircle == null)
break;
Point pt = new Point(Math.round(vCircle[0]), Math.round(vCircle[1]));
int radius = (int)Math.round(vCircle[2]);
Core.circle(bgr, pt, radius, new Scalar(0,255,0), 4, 8, 0);
}
NOTE
1) When i changed minRadius to 90 it detected the outer one instead of the inner but i want smth generic that will work for images/signs not only for this test image.
2) If i converted the Original image into Grey space instead of HSV it detects the outer rather than the inner, but also it is not my case since i have to convert my image into HSV to do Thresholding.
I am writing a program which need to detect red circle-alikes from this picture.
I have tried canny edge detection and find contours but none of them find this red "circles". I also tried to convert this to hsv and detect this by color but I couldn't determine good range for this color, maybe background color confuses it?
I put here a piece of my code with my final attempt..
Mat image = new Mat();
image = Imgcodecs.imread("image.jpg");
Mat hsvImage = new Mat();
Mat grayscaleImage = new Mat();
Mat binaryImage = new Mat();
Imgproc.blur(image, image, new Size(1, 1));
Imgproc.cvtColor(image, hsvImage, Imgproc.COLOR_BGR2HSV);
Imgproc.cvtColor(image, grayscaleImage, Imgproc.COLOR_BGR2GRAY);
Imgproc.equalizeHist(grayscaleImage, grayscaleImage);
Imgproc.Canny(grayscaleImage, grayscaleImage, 50, 150, 3,false);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(grayscaleImage.clone(), contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
for (int id=0;id<contours.size();id++){
MatOfPoint2f mop2f = new MatOfPoint2f();
contours.get(id).convertTo(mop2f,CvType.CV_32F);
RotatedRect rectangle = Imgproc.minAreaRect(mop2f);
if (rectangle.boundingRect().width>80)
Imgproc.drawContours(image,contours,id,new Scalar(0,255,0));
}
If you want to process that marked image, you really might want to detect colors. Typically this is done in HSV color-space.
Here is some C++ code to detect "red" color. The result isn't good enough to use findContours yet, but maybe after some dilation. Maybe you can convert the code to Java.
If you want to detect different color, change the line redMask = thresholdHue(hsv, 0, 20, 50, 50); to mask = thresholdHue(hsv, yourWantedHueColorValue, 20, 50, 50);`
// for example to shift a circluar hue-channel
cv::Mat shiftChannel(cv::Mat H, int shift, int maxVal = 180)
{
// CV_8UC1 only!
cv::Mat shiftedH = H.clone();
//int shift = 25; // in openCV hue values go from 0 to 180 (so have to be doubled to get to 0 .. 360) because of byte range from 0 to 255
for (int j = 0; j < shiftedH.rows; ++j)
for (int i = 0; i < shiftedH.cols; ++i)
{
shiftedH.at<unsigned char>(j, i) = (shiftedH.at<unsigned char>(j, i) + shift) % maxVal;
}
return shiftedH;
}
cv::Mat thresholdHue(cv::Mat hsvImage, int hueVal, int range = 30, int minSat = 50, int minValue = 50)
{
// hsvImage must be CV_8UC3 HSV image.
// hue val and range are in openCV's hue range (0 .. 180)
// range shouldnt be bigger than 90, because that's max (all colors), after shifting the hue channel.
// this function will
// 1. shift the hue channel, so that even colors near the border (red color!) will be detectable with same code.
// 2. threshold the hue channel around the value 90 +/- range
cv::Mat mask; // return-value
std::vector<cv::Mat> channels;
cv::split(hsvImage, channels);
int targetHueVal = 180 / 2; // we'll shift the hue-space so that the target val will always be 90 afterwards, no matter which hue value was chosen. This can be important if
int shift = targetHueVal - hueVal;
if (shift < 0) shift += 180;
cv::Mat shiftedHue = shiftChannel(channels[0], shift, 180);
// merge the channels back to hsv image
std::vector<cv::Mat> newChannels;
newChannels.push_back(shiftedHue);
newChannels.push_back(channels[1]);
newChannels.push_back(channels[2]);
cv::Mat shiftedHSV;
cv::merge(newChannels, shiftedHSV);
// threshold
cv::inRange(shiftedHSV, cv::Vec3b(targetHueVal - range, minSat, minValue), cv::Vec3b(targetHueVal + range, 255, 255), mask);
return mask;
}
int main(int argc, char* argv[])
{
cv::Mat input = cv::imread("C:/StackOverflow/Input/redCircleLikeContours.jpg");
cv::Mat redMask;
cv::Mat hsv;
cv::cvtColor(input, hsv, CV_BGR2HSV);
redMask = thresholdHue(hsv, 0, 20, 50, 50);
cv::imshow("red", redMask);
cv::imshow("input", input);
cv::imwrite("C:/StackOverflow/Output/redCircleLikeContoursMask.png", redMask);
cv::waitKey(0);
return 0;
}
Here's the result:
Here is my code if somebody would want to look :)
public static void main (String args[]){
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat image = new Mat();
image = Imgcodecs.imread("imageorg.jpg");
if ( image == null) System.out.println("Image is fine");
else System.out.println("Wrong path to image");
Mat hsvImage = new Mat();
Imgproc.blur(image, image, new Size(3,3));
Imgproc.cvtColor(image, hsvImage, Imgproc.COLOR_BGR2HSV);
Mat redMask = new Mat();
redMask = thresholdHue(hsvImage,0,20,50,50);
Mat kernel = new Mat();
kernel = Imgproc.getStructuringElement(Imgproc.MORPH_DILATE, new Size(2,2));
Mat dilateMat = new Mat();
Imgproc.dilate(redMask, dilateMat, kernel);
Imgcodecs.imwrite("redCircleLikeContours.png", redMask);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(dilateMat.clone(), contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
List<MatOfPoint> removedContoursList = new ArrayList<MatOfPoint>();
for (int id=0;id<contours.size();id++){
MatOfPoint2f mop2f = new MatOfPoint2f();
contours.get(id).convertTo(mop2f,CvType.CV_32F);
RotatedRect rectangle = Imgproc.minAreaRect(mop2f);
if (rectangle.boundingRect().height<10){
removedContoursList.add(contours.get(id));
System.out.println("removing: "+rectangle.boundingRect());
contours.remove(id);
id--;
}
}
}
public static Mat thresholdHue(Mat hsvImage, int hueVal, int range, int minSat, int minValue)
{
Mat mask = new Mat();
List<Mat> channels = new ArrayList<Mat>();
Core.split(hsvImage, channels);
int targetHueVal = 180 / 2;
int shift = targetHueVal - hueVal;
if (shift < 0) shift += 180;
Mat shiftedHue = shiftChannel(channels.get(0), shift, 180);
List<Mat> newChannels = new ArrayList<Mat>();
newChannels.add(shiftedHue);
newChannels.add(channels.get(1));
newChannels.add(channels.get(2));
Mat shiftedHSV = new Mat();
Core.merge(newChannels, shiftedHSV);
Core.inRange(shiftedHSV, new Scalar(targetHueVal - range, minSat, minValue), new Scalar(targetHueVal + range, 255, 255), mask);
return mask;
}
private static Mat shiftChannel(Mat H, int shift, int maxVal)
{
Mat shiftedH = H.clone();
for (int j = 0; j < shiftedH.rows(); ++j)
for (int i = 0; i < shiftedH.cols(); ++i)
{
shiftedH.put(j, i,(shiftedH.get(j,i)[0] + shift) % maxVal);
}
return shiftedH;
}
I'm doing a project using opencv in android studio.
My project is about comparing colour histogram of an input image captured by camera with the 6 images that is stored in the drawable. The opencv function that I used is comparHist(). The purpose of the comparison is to know if the input image has matched colour to any images in the drawable.
My problem is I need to calculate colour histogram using calcHist() for every 6 images every time there is an input image(captured by camera) so that I can compare them. I was thinking to store the colour histogram value of 6 images in an array. Can I do so?
I was searching for a solution but there is none. Here is my code that I have done.
public int resultRecog() {
drawImg = BitmapFactory.decodeResource(getResources(), R.drawable.onefront);
Mat hsv_base = new Mat();
Mat hsv_test = new Mat();
Utils.bitmapToMat(drawImg, hsv_base);
Utils.bitmapToMat(pic, hsv_test);
/// Convert to HSV
Imgproc.cvtColor(hsv_base, hsv_base, Imgproc.COLOR_BGR2HSV);
Imgproc.cvtColor(hsv_test, hsv_test, Imgproc.COLOR_BGR2HSV);
/// h s bins value
MatOfInt histSize = new MatOfInt(40, 40);
//// ranges h=0-180, s=0-256
MatOfFloat ranges = new MatOfFloat(0f, 180f, 0f, 256f);
/// two channel
MatOfInt channels = new MatOfInt(0, 1);
Mat hist_base = new Mat();
Mat hist_test = new Mat();
ArrayList<Mat> histImages = new ArrayList<Mat>();
histImages.add(hsv_base);
Imgproc.calcHist(histImages, channels, new Mat(), hist_base, histSize, ranges, false);
Core.normalize(hist_base, hist_base, 0, 1, Core.NORM_MINMAX, -1, new Mat());
histImages = new ArrayList<Mat>();
histImages.add(hsv_test);
Imgproc.calcHist(histImages, channels, new Mat(), hist_test, histSize, ranges, false);
Core.normalize(hist_test, hist_test, 0, 1, Core.NORM_MINMAX, -1, new Mat());
double result = Imgproc.compareHist(hist_base, hist_test, 0);
drawImg.recycle();
drawImg = null;
int r;
if (result >= 0.15) {
r = 1;
} else {
drawImg = BitmapFactory.decodeResource(getResources(), R.drawable.fivefront);
Mat hsv_base5 = new Mat();
Utils.bitmapToMat(drawImg, hsv_base5);
Imgproc.cvtColor(hsv_base5, hsv_base5, Imgproc.COLOR_BGR2HSV);
Mat hist_base5 = new Mat();
ArrayList<Mat> histImages5 = new ArrayList<Mat>();
histImages5.add(hsv_base5);
Imgproc.calcHist(histImages5, channels, new Mat(), hist_base5, histSize, ranges, false);
Core.normalize(hist_base5, hist_base5, 0, 1, Core.NORM_MINMAX, -1, new Mat());
result = Imgproc.compareHist(hist_base5, hist_test, 0);
drawImg.recycle();
drawImg = null;
if (result >= 0.1) {
r = 5;
} else {
drawImg = BitmapFactory.decodeResource(getResources(), R.drawable.f10);
Mat hsv_base10 = new Mat();
Utils.bitmapToMat(drawImg, hsv_base10);
Imgproc.cvtColor(hsv_base10, hsv_base10, Imgproc.COLOR_BGR2HSV);
Mat hist_base10 = new Mat();
ArrayList<Mat> histImages10 = new ArrayList<Mat>();
histImages10.add(hsv_base10);
Imgproc.calcHist(histImages10, channels, new Mat(), hist_base10, histSize, ranges, false);
Core.normalize(hist_base10, hist_base10, 0, 1, Core.NORM_MINMAX, -1, new Mat());
result = Imgproc.compareHist(hist_base10, hist_test, 0);
drawImg.recycle();
drawImg = null;
if (result >= 0.1) {
r = 10;
} else {
drawImg = BitmapFactory.decodeResource(getResources(), R.drawable.fiftyfront);
Mat hsv_base50 = new Mat();
Utils.bitmapToMat(drawImg, hsv_base50);
Imgproc.cvtColor(hsv_base50, hsv_base50, Imgproc.COLOR_BGR2HSV);
Mat hist_base50 = new Mat();
ArrayList<Mat> histImages50 = new ArrayList<Mat>();
histImages50.add(hsv_base50);
Imgproc.calcHist(histImages50, channels, new Mat(), hist_base50, histSize, ranges, false);
Core.normalize(hist_base50, hist_base50, 0, 1, Core.NORM_MINMAX, -1, new Mat());
result = Imgproc.compareHist(hist_base50, hist_test, 0);
drawImg.recycle();
drawImg = null;
if (result >= 0.1) {
r = 50;
} else {
r = 0;
}
}//rm10
}//rm5
}//rm1
return r;
}
So my question is, can I store the colour histogram value (of 6 images stored in the drawable) in an array so that the application doesn't need to re-calculate the colour histogram every time there is input image captured by camera
I'm developing a Android app to detect vehicle number plate. i did image processing up to findContours level of image. Now i need to convert following C++ code to Opencv Based Android java.
This is original image
This is after Otsu thresholding image
This is my andoid+opencv code (working 100%)
ImageView imgView = (ImageView) findViewById(R.id.imageView1);
Bitmap bmp = BitmapFactory.decodeResource(getResources(),car);
//First convert Bitmap to Mat
Mat ImageMatin = new Mat ( bmp.getHeight(), bmp.getWidth(), CvType.CV_8U, new Scalar(4));
Mat ImageMatout = new Mat ( bmp.getHeight(), bmp.getWidth(), CvType.CV_8U, new Scalar(4));
Mat ImageMatBk = new Mat ( bmp.getHeight(), bmp.getWidth(), CvType.CV_8U, new Scalar(4));
Mat ImageMatTopHat = new Mat ( bmp.getHeight(), bmp.getWidth(), CvType.CV_8U, new Scalar(4));
Mat temp = new Mat ( bmp.getHeight(), bmp.getWidth(), CvType.CV_8U, new Scalar(4));
Bitmap myBitmap32 = bmp.copy(Bitmap.Config.ARGB_8888, true);
Utils.bitmapToMat(myBitmap32, ImageMatin);
//Converting RGB to Gray.
Imgproc.cvtColor(ImageMatin, ImageMatBk, Imgproc.COLOR_RGB2GRAY,8);
Imgproc.dilate(ImageMatBk, temp, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(9, 9)));
Imgproc.erode(temp, ImageMatTopHat, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(9,9)));
//Core.absdiff(current, previous, difference);
Core.absdiff(ImageMatTopHat, ImageMatBk, ImageMatout);
//Sobel operator in horizontal direction.
Imgproc.Sobel(ImageMatout,ImageMatout,CvType.CV_8U,1,0,3,1,0.4,Imgproc.BORDER_DEFAULT);
//Converting GaussianBlur
Imgproc.GaussianBlur(ImageMatout, ImageMatout, new Size(5,5),2);
Imgproc.dilate(ImageMatout, ImageMatout, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3,3)));
Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(17, 3));
Imgproc.morphologyEx(ImageMatout, ImageMatout, Imgproc.MORPH_CLOSE, element);
//threshold image
Imgproc.threshold(ImageMatout, ImageMatout, 0, 255, Imgproc.THRESH_OTSU+Imgproc.THRESH_BINARY);
Now I need to extract number Plate
Please help me to convert following C++ code to java+opencv:.
std::vector rects;
std::vector<std::vector >::iterator itc = contours.begin();
while (itc != contours.end())
{
cv::RotatedRect mr = cv::minAreaRect(cv::Mat(*itc));
float area = fabs(cv::contourArea(*itc));
float bbArea=mr.size.width * mr.size.height;
float ratio = area/bbArea;
if( (ratio < 0.45) || (bbArea < 400) ){
itc= contours.erase(itc);
}else{
++itc;
rects.push_back(mr);
}
}
Looking at http://docs.opencv.org/java and the documentation for findContours in particular
instead of
std::vector<std::vector<cv::Point> > contours;
you will have
java.util.ArrayList<MatOfPoint> contours;
You can use contours.listIterator() to traverse the list. Something like the below (not compiled let alone run,likely to contain major blunders):
import java.util.*;
import org.opencv.imgproc.Imgproc;
import org.opencv.core.*;
/* ... */
ArrayList<RotatedRect> rects = new ArrayList<RotatedRect>()
ArrayList<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(image, contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_NONE);
ListIterator<MatOfPoint> itc = contours.listIterator();
while(itc.hasNext())
{
MatOfPoint2f mp2f = new MatOfPoint2f(itc.next().toArray());
RotatedRect mr = Imgproc.minAreaRect(mp2f);
double area = Math.abs(Imgproc.contourArea(mp2f));
double bbArea= mr.size.area();
double ratio = area / bbArea;
if( (ratio < 0.45) || (bbArea < 400) )
{
itc.remove(); // other than deliberately making the program slow,
// does erasing the contour have any purpose?
}
else
{
rects.add(mr);
}
}
Actually, i want to find out the dominant colour in the image, so i want to find the HSV histogram of the image and hence filter out the other colours. However, i dont know how to do this in java platform using opence. I only find the code in C++. Thank you.
Mat image = Highgui.imread("binary07.jpg");
//Mat src = new Mat(image.height(), image.width(), CvType.CV_8UC2);
Imgproc.cvtColor(image, image, Imgproc.COLOR_RGB2GRAY);
List<Mat> hsv_planes = new ArrayList<Mat>();
Core.split(image, hsv_planes);
MatOfInt histSize = new MatOfInt(256);
final MatOfFloat histRange = new MatOfFloat(0f, 256f);
boolean accumulate = false;
Mat h_hist = new Mat();
Mat s_hist = new Mat();
Mat v_hist = new Mat();
//error appear in the following sentences
Imgproc.calcHist((List<Mat>) hsv_planes.get(0), new MatOfInt(3), new Mat(), h_hist, histSize, histRange, accumulate);
Imgproc.calcHist((List<Mat>) hsv_planes.get(1), new MatOfInt(3), new Mat(), s_hist, histSize, histRange, accumulate);
Imgproc.calcHist((List<Mat>) hsv_planes.get(2), new MatOfInt(3), new Mat(), v_hist, histSize, histRange, accumulate);
int hist_w = 512;
int hist_h = 600;
long bin_w = Math.round((double) hist_w / 256);
//bin_w = Math.round((double) (hist_w / 256));
Mat histImage = new Mat(hist_h, hist_w, CvType.CV_8UC1);
Core.normalize(h_hist, h_hist, 3, histImage.rows(), Core.NORM_MINMAX);
Core.normalize(s_hist, s_hist, 3, histImage.rows(), Core.NORM_MINMAX);
Core.normalize(v_hist, v_hist, 3, histImage.rows(), Core.NORM_MINMAX);
for (int i = 1; i < 256; i++) {
Point p1 = new Point(bin_w * (i - 1), hist_h - Math.round(h_hist.get(i - 1, 0)[0]));
Point p2 = new Point(bin_w * (i), hist_h - Math.round(h_hist.get(i, 0)[0]));
Core.line(histImage, p1, p2, new Scalar(255, 0, 0), 2, 8, 0);
Point p3 = new Point(bin_w * (i - 1), hist_h - Math.round(s_hist.get(i - 1, 0)[0]));
Point p4 = new Point(bin_w * (i), hist_h - Math.round(s_hist.get(i, 0)[0]));
Core.line(histImage, p3, p4, new Scalar(0, 255, 0), 2, 8, 0);
Point p5 = new Point(bin_w * (i - 1), hist_h - Math.round(v_hist.get(i - 1, 0)[0]));
Point p6 = new Point(bin_w * (i), hist_h - Math.round(v_hist.get(i, 0)[0]));
Core.line(histImage, p5, p6, new Scalar(0, 0, 255), 2, 8, 0);
}
Highgui.imwrite("histogram.jpg", histImage);
I dont know how to get the output after the split function.
reference:
http://docs.opencv.org/java/
http://docs.opencv.org/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.html
In the code, the color conversion:
Imgproc.cvtColor(image, image, Imgproc.COLOR_RGB2GRAY);
should be to HSV not gray:
Imgproc.cvtColor(image, image, Imgproc.COLOR_BGR2HSV);
In your example you will only have one (gray) plane instead of the 3 HSV channels. That will give errors when you access the 2nd and 3rd plane.
Here is the code for comparing the histogram of Source image to a reference image for OpenCV 2.4.11 Java (Android).
// Assume SourceImage is a Bitmap ARGB_8888
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap refImage = BitmapFactory.decodeFile(mBaseDir + "some_reference.jpg", options);
Mat hsvRef = new Mat();
Mat hsvSource = new Mat();
Mat srcRef = new Mat(refImage.getHeight(), refImage.getWidth(), CvType.CV_8U, new Scalar(4));
Utils.bitmapToMat(refImage, srcRef);
Mat srcSource = new Mat(SourceImage.getHeight(), SourceImage.getWidth(), CvType.CV_8U, new Scalar(4));
Utils.bitmapToMat(SourceImage, srcSource);
/// Convert to HSV
Imgproc.cvtColor(srcRef, hsvRef, Imgproc.COLOR_BGR2HSV);
Imgproc.cvtColor(srcSource, hsvSource, Imgproc.COLOR_BGR2HSV);
/// Using 50 bins for hue and 60 for saturation
int hBins = 50;
int sBins = 60;
MatOfInt histSize = new MatOfInt( hBins, sBins);
// hue varies from 0 to 179, saturation from 0 to 255
MatOfFloat ranges = new MatOfFloat( 0f,180f,0f,256f );
// we compute the histogram from the 0-th and 1-st channels
MatOfInt channels = new MatOfInt(0, 1);
Mat histRef = new Mat();
Mat histSource = new Mat();
ArrayList<Mat> histImages=new ArrayList<Mat>();
histImages.add(hsvRef);
Imgproc.calcHist(histImages,
channels,
new Mat(),
histRef,
histSize,
ranges,
false);
Core.normalize(histRef,
histRef,
0,
1,
Core.NORM_MINMAX,
-1,
new Mat());
histImages=new ArrayList<Mat>();
histImages.add(hsvSource);
Imgproc.calcHist(histImages,
channels,
new Mat(),
histSource,
histSize,
ranges,
false);
Core.normalize(histSource,
histSource,
0,
1,
Core.NORM_MINMAX,
-1,
new Mat());
double resp1 = Imgproc.compareHist(histRef, histSource, 0);
double resp2 = Imgproc.compareHist(histRef, histSource, 1);
double resp3 = Imgproc.compareHist(histRef, histSource, 2);
double resp4 = Imgproc.compareHist(histRef, histSource, 3);
The next code works fine for one depth channel. You have to do just a few modifications to add the other two channels
//Calculate histogram
java.util.List<Mat> matList = new LinkedList<Mat>();
matList.add(imageIR_gray);
Mat histogram = new Mat();
MatOfFloat ranges=new MatOfFloat(0,256);
MatOfInt histSize = new MatOfInt(255);
Imgproc.calcHist(
matList,
new MatOfInt(0),
new Mat(),
histogram ,
histSize ,
ranges);
// Create space for histogram image
Mat histImage = Mat.zeros( 100, (int)histSize.get(0, 0)[0], CvType.CV_8UC1);
// Normalize histogram
Core.normalize(histogram, histogram, 1, histImage.rows() , Core.NORM_MINMAX, -1, new Mat() );
// Draw lines for histogram points
for( int i = 0; i < (int)histSize.get(0, 0)[0]; i++ )
{
Core.line(
histImage,
new org.opencv.core.Point( i, histImage.rows() ),
new org.opencv.core.Point( i, histImage.rows()-Math.round( histogram.get(i,0)[0] )) ,
new Scalar( 255, 255, 255),
1, 8, 0 );
}