In the last tutorial we’ve covered OpenCV and Android Studio project integration. This time we’ll try to make actual use of this setup. A code sample that we’ve used in a commercial Android application can be found on our GitHub page.
Extract the data from an image
An image histogram is a chart that represents the distribution (frequency of occurrence) of pixels within an image.
To calculate the input data, the best option is to use the Imgproc.calcHist
method, provided OpenCV. It will help us to create the histogram from a set of arrays (mostly image data).
// Create the required arrays and convert the bitmap (our image)
// so that it fits the array.
Mat rgba = new Mat();
Utils.bitmapToMat(bitmap, rgba);
// Get the bitmap size.
Size rgbaSize = rgba.size();
Now we are ready to configure our histograms:
// Set the amount of bars in the histogram.
int histSize = 256;
MatOfInt histogramSize = new MatOfInt(histSize);
// Set the height of the histogram and width of the bar.
int histogramHeight = (int) rgbaSize.height;
int binWidth = 5;
// Set the value range.
MatOfFloat histogramRange = new MatOfFloat(0f, 256f);
// Create two separate lists: one for colors and one for channels (these will be used as separate datasets).
Scalar[] colorsRgb = new Scalar[]{new Scalar(200, 0, 0, 255), new Scalar(0, 200, 0, 255), new Scalar(0, 0, 200, 255)};
MatOfInt[] channels = new MatOfInt[]{new MatOfInt(0), new MatOfInt(1), new MatOfInt(2)};
// Create an array to be saved in the histogram and a second array, on which the histogram chart will be drawn.
Mat[] histograms = new Mat[]{new Mat(), new Mat(), new Mat()};
Mat histMatBitmap = new Mat(rgbaSize, rgba.type());
Separating channels
Now we must calculate the histogram for each channel, standardize the datasets and then draw it.
for (int i = 0; i < channels.length; i++) {
Imgproc.calcHist(Collections.singletonList(rgba), channels[i], new Mat(), histograms[i], histogramSize, histogramRange);
Core.normalize(histograms[i], histograms[i], histogramHeight, 0, Core.NORM_INF);
for (int j = 0; j < histSize; j++) {
Point p1 = new Point(binWidth * (j - 1), histogramHeight - Math.round(histograms[i].get(j - 1, 0)[0]));
Point p2 = new Point(binWidth * j, histogramHeight - Math.round(histograms[i].get(j, 0)[0]));
Imgproc.line(histMatBitmap, p1, p2, colorsRgb[i], 2, 8, 0);
}
}
Using the Imgproc.calcHist
method, calculate the histogram for each channel. The following parameters can be used:
List<Mat> images
: array photos listMatOflnt channels
: channels listMat mask
: optional maskMat hist
: an array in which the calculations will be savedMatOflnt histSize
: the amount of the bars for every used dimensionMatOfFloat rangers
: the value range measured for all the dimensions
Normalize the data
After calculating the histogram, standardize it in such a way so his values fit into the range indicated by the given parameters according to the Core.normalize
method.
The method takes the following parameters:
Mat src
: a source arrayMat dst
: an initial arraydouble alpha
double beta
int norm_type
Draw the chart
In the second for loop, we create points for each histogram bar and draw a line based on that.
for (int j = 0; j < histSize; j++) {
Point p1 = new Point(binWidth * (j - 1), histogramHeight - Math.round(histograms[i].get(j - 1, 0)[0]));
Point p2 = new Point(binWidth * j, histogramHeight - Math.round(histograms[i].get(j, 0)[0]));
Imgproc.line(histMatBitmap, p1, p2, colorsRgb[i], 2, 8, 0);
}
At the end we display our initial bitmap and create a second one (made out of our arrays) to be displayed as well.
// Don't do that at home or work. It's for visualization purpose.
BitmapHelper.showBitmap(this, bitmap, imageView);
Bitmap histBitmap = Bitmap.createBitmap(histMatBitmap.cols(), histMatBitmap.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(histMatBitmap, histBitmap);
BitmapHelper.showBitmap(this, histBitmap, histogramView);
That’s all! Let’s see the result here:
As you can see, it’s much easier to calculate and draw a histogram with OpenCV itself when building an Android app.
A code sample that we’ve used in a commercial Android application can be found on our GitHub page.
Popular posts
From Hype to Hard Hats: Practical Use Cases for AI chatbots in Construction and Proptech.
Remember the multimedia craze in the early 2000s? It was everywhere, but did it truly revolutionize our lives? Probably not. Today, it feels like every piece of software is labeled "AI-powered." It's easy to dismiss AI chatbots in construction as just another tech fad.
Read moreFears surrounding external support. How to address concerns about outsourcing software development?
Whether you’ve had bad experiences in the past or no experience at all, there will always be fears underlying your decision to outsource software development.
Read moreWhat do you actually seek from external support? Identify what’s preventing you from completing a project on time and within budget
Let’s make it clear: if the capabilities are there, a project is best delivered internally. Sometimes, however, we are missing certain capabilities that are required to deliver said project in a realistic timeline. These may be related to skills (e.g. technical expertise, domain experience), budget (hiring locally is too expensive) or just capacity (not enough manpower). What are good reasons for outsourcing software development?
Read more