how to use opencv to calculate HSV histogram in java platform?
实际上,我想找出图像中的主色,所以我想找到图像的 HSV 直方图,从而过滤掉其他颜色。但是,我不知道如何在使用 opence 的 java 平台中执行此操作。我只在 C 中找到代码。谢谢。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 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); |
我不知道如何得到拆分函数后的输出。
参考:
http://docs.opencv.org/java/
http://docs.opencv.org/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.html
在代码中,颜色转换:
1 | Imgproc.cvtColor(image, image, Imgproc.COLOR_RGB2GRAY); |
应该是HSV而不是灰色:
1 | Imgproc.cvtColor(image, image, Imgproc.COLOR_BGR2HSV); |
在您的示例中,您将只有一个(灰色)平面,而不是 3 个 HSV 通道。当您访问第 2 和第 3 平面时,这会出错。
这里是将源图像的直方图与 OpenCV 2.4.11 Java (Android) 的参考图像进行比较的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | // 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); |
下一个代码适用于一个深度通道。您只需进行一些修改即可添加其他两个频道
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | //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 ); } |