Detect Values of RGB from CameraFrame using OpenCV in Android - android

I want to detect which value is maximum from RGB. how can I detect that?
I want to display which colour has highest occurrence with their
RGB value. For example, In a image the RED colour has highest occurrence so it will display colour as RED and with their value in percentage.
I have tried it by getting rows and cols of image like below:
public Mat onCameraFrame(CvCameraViewFrame cvf) {
mRgba = cvf.rgba();
int rows = mRgba.rows();
int cols = mRgba.cols();
// int ch = mRgba.channels();
double R=0,G=0,B=0;
for (int i=0; i<rows; i++)
{
for (int j=0; j<cols; j++)
{
double[] data = mRgba.get(i, j); //Stores element in an array
R = data[0];
G= data[1];
B = data[2];
}
}
Imgproc.putText(mRgba,"R:"+R + "G:"+G +"B:"+B,new Point(10,52),Core.FONT_HERSHEY_COMPLEX,.7,new Scalar(5,255,255), 2,8,false );
return mRgba;
}
but it is taking to much time and screen is lagging because I have implemented code in onCameraFrame. So how can I detect it fast in this method and which is the best way to it?
Thanks.

For such tasks you should use AsyncTask as it does not run on MainThread thus your UI wont freeze.
https://developer.android.com/reference/android/os/AsyncTask.html
I assume that this will be faster compared to your current solution.

Split the image into its R, G and B channels, and compute the sum of each Mat.
vector<Mat> channels;
split(mRgba, channels);
B = sum(channels[0])[0];
G = sum(channels[1])[0];
R = sum(channels[2])[0];
Compare the values of R, G and B to know which colour has occurred the most in the frame.

Related

Android YUV to grayscale performance optimization

I'm trying to convert an YUV image to grayscale, so basically I just need the Y values.
To do so I wrote this little piece of code (with frame being the YUV image):
imageConversionTime = System.currentTimeMillis();
size = frame.getSize();
byte nv21ByteArray[] = frame.getImage();
int lol;
for (int i = 0; i < size.width; i++) {
for (int j = 0; j < size.height; j++) {
lol = size.width*j + i;
yMatrix.put(j, i, nv21ByteArray[lol]);
}
}
bitmap = Bitmap.createBitmap(size.width, size.height, Bitmap.Config.ARGB_8888);
Utils.matToBitmap(yMatrix, bitmap);
imageConversionTime = System.currentTimeMillis() - imageConversionTime;
However, this takes about 13500 ms. I need it to be A LOT faster (on my computer it takes 8.5 ms in python) (I work on a Motorola Moto E 4G 2nd generation, not super powerful but it should be enough for converting images right?).
Any suggestions?
Thanks in advance.
First of all I would assign size.width and size.height to a variable. I don't think the compiler will optimize this by default, but I am not sure about this.
Furthermore Create a byte[] representing the result instead of using a Matrix.
Then you could do something like this:
int[] grayScalePixels = new int[size.width * size.height];
int cntPixels = 0;
In your inner loop set
grayScalePixels[cntPixels] = nv21ByteArray[lol];
cntPixels++;
To get your final image do the following:
Bitmap grayScaleBitmap = Bitmap.createBitmap(grayScalePixels, size.width, size.height, Bitmap.Config.ARGB_8888);
Hope it works properly (I have not tested it, however at least the shown principle should be applicable -> relying on a byte[] instead of Matrix)
Probably 2 years too late but anyways ;)
To convert to gray scale, all you need to do is set the u/v values to 128 and leave the y values as is. Note that this code is for YUY2 format. You can refer to this document for other formats.
private void convertToBW(byte[] ptrIn, String filePath) {
// change all u and v values to 127 (cause 128 will cause byte overflow)
byte[] ptrOut = Arrays.copyOf(ptrIn, ptrIn.length);
for (int i = 0, ptrInLength = ptrOut.length; i < ptrInLength; i++) {
if (i % 2 != 0) {
ptrOut[i] = (byte) 127;
}
}
convertToJpeg(ptrOut, filePath);
}
For NV21/NV12, I think the loop would change to:
for (int i = ptrOut.length/2, ptrInLength = ptrOut.length; i < ptrInLength; i++) {}
Note: (didn't try this myself)
Also I would suggest to profile your utils method and createBitmap functions separately.

Having problems using setPixel() method

Can someone explain me the way setPixel() method works in Android? I am trying to replace some pixels on a bitmap. I extract them by using getPixel() method and their individual colors, eg.green = Color.green(a[i][j]);, but I cannot set them new values back, so as to show the processed image onscreen.
Edit: This is where some of the processing occurs. I try to algorithmically convert to grayscale
for (int i = 0; i < grayWidth; i++) {
for (int j = 0; j < grayHeight; j++) {
a[i][j] = myImage.getPixel(i, j);
red = Color.red(a[i][j]);
green = Color.green(a[i][j]);
blue = Color.blue(a[i][j]);
gray = (red + green + blue) / 3;
a[i][j] = gray;
}
}
and then replace pixels:
for (int m = 0; m < grayHeight; m++) {
for (int n = 0; n < grayWidth; n++) {
grayScale.setPixel(m, n, a[m][n]);
}
}
and finally show it on-screen
imageView.setImageBitmap(grayScale);
Sorry for not explaining it thoroughly in the first place/
Why posts questions without any code? Put yourself in our position, how can we help you, if we do not know what you are trying to do? You're only presenting your problem in English language, which does not equal to programming language in most cases. We want to see the latter, supported with english description of what you are doing and what's going on.
Based on provided information and Android Dev Page for Bitmap, I can assume that your BitMap image might not be mutable. This would throw then IllegalStateException, but without seeing your LogCat / Code, I cannot be sure, whether this is the case.
If the BitMap indeed is immutable, then you can try and look at converting immutable bitmap to mutable and try again.

How to copy the elements of 1D int array to MxN Mat in Open CV java?

I am new to open CV and android. I want to copy the elements of a 1D integer array to a Mat such that the first row of Mat consists of all the elements of the 1D array, the second row of Mat should consist of the next 1D int array and so on. So, if there are 'M' number of 1D int arrays of length 'N', the Mat should be M X N. Can we do this using the .put(int row, int col, int[] data). If so, then how? The open CV documentation on .put is not very clear. http://docs.opencv.org/java/2.4.2/org/opencv/core/Mat.html
Here is my code,
int[] features;
Mat trainingData = new Mat();
features = FindFeatures(mRgba.width(), mRgba.height(), yuv, rgba);
After this I need to fill my trainingData from the features Int array such that for 'M' features of length 'N', I get a Mat of M X N. Using this M X N Mat, I will be a able to train the SVM.
If I understand your question correct, you can use the put method: http://docs.opencv.org/java/2.4.2/org/opencv/core/Mat.html#put(int,%20int,%20int[])
And end up with a method looking like this:
public void fillMatrinx(Mat matrix, int col, int row, int[][] data)
{
for(int i = 0; i < row; i++)
{
int n = 0;
for(int j = 0; j < col; j++)
{
matrix.put(i,j,data[i][n]);
n++;
}
}
}

how to get pixel color using byte array in Android

In my Android project,
Here is my code.
for (int x = 0; x < targetBitArray.length; x += weight) {
for (int y = 0; y < targetBitArray[x].length; y += weight) {
targetBitArray[x][y] = bmp.getPixel(x, y) == mSearchColor;
}
}
but this code wastes a lot of time.
So I need to find way faster than bitmap.getPixel().
I'm trying to get pixel color using byte array converted from bitmap, but I can't.
How to replace Bitmap.getPixel()?
Each Bitmap.getPixel method invocation requires a lot of resources, so you need to avoid the amount of requests in order to improve the performace of your code.
My suggestion is:
Read the image data row-by-row with Bitmap.getPixels method into a local array
Iterate along your local array
e.g.
int [] rowData= new int [bitmapWidth];
for (int row = 0; row < bitmapHeight; row ++) {
// Load row of pixels
bitmap.getPixels(rowData, 0, bitmapWidth, 0, row, bitmapWidth, 1);
for (int column = 0; column < bitmapWidth; column ++) {
targetBitArray[column][row] = rowData(column) == mSearchColor;
}
}
This will be a great improvement for the performace of your code

extract a vector of pixels from a frame using OpenCV?

I'am actually working in a project on android in which I want to extract some specific pixel values (according to a condition, using the threshold method , I have set some pixels to a certain values and all the others to zero) I want to extract all these values different from zero in a vector. I will use this vector of the chosen pixels to do some operation ( the mean value for exemple ) , Is there a method in OpenCV that can help me doing this ?
Thank you :)
I don't know such function but actually it's not hard to implement it (c++):
//'in' should be CV_8UC3
vector<int>& getNonZero(const Mat& in)
{
//get size of result vector
//this is all non-zero pixels:
int count = countNonZero(in);
vector<int>& result(count);
int k = 0;
for (int r = 0; r < in.rows; ++r)
{
for (int c = 0; c < in.cols; ++c)
{
if (in.at<int>(r, c))
{
result[k++] = in.at<int>(r, c);
}
}
}
return result;
}
And also many OpenCV functions have InputArray mask parameter so use it! For example:
void meanStdDev(InputArray src, OutputArray mean, OutputArray stddev, InputArray mask=noArray())

Categories

Resources