my goal is to display a threshed image using the HSV color space in a way that only yellow objects will be shown. i use this code (based on a code given by the openCV 2.3.1 android samples):
protected Bitmap processFrame(VideoCapture capture) {
//capture.retrieve(mGray, Highgui.CV_CAP_ANDROID_GREY_FRAME);
//Imgproc.cvtColor(mGray, mRgba, Imgproc.COLOR_GRAY2RGBA, 4);
capture.retrieve(mHSV, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
Imgproc.cvtColor(mHSV, mRgba, Imgproc.COLOR_RGB2HSV, 4);
//Core.inRange(mRgba, new Scalar(20, 100, 100), new Scalar(30, 255, 255), mRgba);
Bitmap bmp = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(), Bitmap.Config.ARGB_8888);
if (Utils.matToBitmap(mRgba, bmp))
return bmp;
bmp.recycle();
return null;
}
the base (Abstract)class contains the "run" method:
protected abstract Bitmap processFrame(VideoCapture capture);
public void run() {
...
bmp = processFrame(mCamera);
...
canvas.drawBitmap(bmp, (canvas.getWidth() - bmp.getWidth()) / 2, (canvas.getHeight() - bmp.getHeight()) / 2, null);
...
}
i get this distorted preview which i think i can understand (HSV format) but why is it repeating itself (i`v draw a green line to emphasize it) 4 time? and what is the black horizontal line?
what am i doing wrong?
one last thing, what is the logic behind:
Imgproc.cvtColor(mHSV, mRgba, Imgproc.COLOR_RGB2HSV, 4);
why is it COLOR_RGB2HSV? shouldnt it be COLOR_HSV2RGB?
Let's say i'v passed this problem, how can i make a gray level image with the yellow objects in their native color? i thought using the Core.inRange() method but when i do this i get black screen.
yes, i guess i look like a total jerk but i need to start from somewhere, don't i?
10x!
Update 1:
i tried to do RGB->HSV->RGB this way:
#Override
protected Bitmap processFrame(VideoCapture capture) {
//capture.retrieve(mGray, Highgui.CV_CAP_ANDROID_GREY_FRAME);
//Imgproc.cvtColor(mGray, mRgba, Imgproc.COLOR_GRAY2RGBA, 4);
capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGB);
Imgproc.cvtColor(mRgba, mHSV, Imgproc.COLOR_RGB2HSV,0);
//Imgproc.cvtColor(mRgba, mRgba, Imgproc.COLOR_BGR2RGB, 4);
//Core.inRange(mRgba, new Scalar(20, 100, 100), new Scalar(30, 255, 255), mRgba);
Imgproc.cvtColor(mHSV,mRgba , Imgproc.COLOR_HSV2RGB,0);
Bitmap bmp = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(), Bitmap.Config.ARGB_8888);
if (Utils.matToBitmap(mRgba, bmp))
return bmp;
bmp.recycle();
return null;
}
and i got:
?
Update 2:
i finally understand that before setting a frame, it must be converted into RGBA space.
so i now tried the threshold with the code as follow:
capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
Imgproc.cvtColor(mRgba, mHSV, Imgproc.COLOR_RGB2HSV,0);
Core.inRange(mHSV, new Scalar(20, 100, 100), new Scalar(30, 255, 255), mHSVThreshed);
Imgproc.cvtColor(mHSVThreshed, mRgba, Imgproc.COLOR_HSV2RGB, 0);
Imgproc.cvtColor(mRgba, mRgba, Imgproc.COLOR_RGB2RGBA, 0);
Bitmap bmp = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(), Bitmap.Config.ARGB_8888);
but now it gives me force shutdown... any ideas?
friends. i give you the result of 1 month of hard work and help from friends across the ocean:
Ethan was right. but the code needed some fixing.
the code:
capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_BGRA);
Imgproc.cvtColor(mRgba, mHSV, Imgproc.COLOR_BGR2HSV,3);
Core.inRange(mHSV, new Scalar(0, 100, 30), new Scalar(5, 255, 255), mHSVThreshed);
Imgproc.cvtColor(mHSVThreshed, mRgba, Imgproc.COLOR_GRAY2BGR, 0);
Imgproc.cvtColor(mRgba, mRgba2, Imgproc.COLOR_BGR2RGBA, 0);
Bitmap bmp = Bitmap.createBitmap(mRgba2.cols(), mRgba2.rows(), Bitmap.Config.ARGB_8888);
if (Utils.matToBitmap(mRgba2, bmp))...
first, the mat is binary 0 or 255 so the transform to gray level is more "natural". second, the conversion from HSVto RGBis in fact HSV-BGR!!. and last thing is that the preview is expecting RGBA Bitmap.
thats it. hope other can benefit from this post. SHALOM!
I think mHSVThreshed is a binary mat
so maybe this line :
Imgproc.cvtColor(mHSVThreshed, mRgba, Imgproc.COLOR_HSV2RGB, 0);
should change to :
Imgproc.cvtColor(mHSVThreshed, mRgba, Imgproc.COLOR_GRAY2RGB, 0);
I spent a lot of time dealing with the "showing" problem too...
hope this help...
Well as far as I see it you fetch the image frame in RGBA and save it under the name "mHSV"
capture.retrieve(mHSV, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
so you should there store it as mRgba
in the cvtColor you need to transform it to HSV via COLOR_RGBA2HSV. Assuming you have changed the names this would be:
Imgproc.cvtColor(mRgba, mRSV, Imgproc.COLOR_RGB2HSV, 0);
And I assume this repetition of the images comes from the "4" in you cvtColor function since your HSV picture will only have 3 channels. Put in a 0 there and it should be detected automatically...
I hope it helps...
why is it COLOR_RGB2HSV? shouldnt it be COLOR_HSV2RGB?
I would say that it should :).
Looks like a problem on how opencv grabs the pixels. Check that both your input and output images have the same size and numberof channels.
This
capture.retrieve(mHSV, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
looks also weird to me, Are you storing the RGBA image that you get into an image at HSV format?
That would explain the problem.
Try to do something like that : RGB(capture retrieve) => HSV(cvt color) => color detection => RGB (cvt color again)
Related
I am using OpenCV android library thresholding method for image segmentation, but the problem is that the output bitmap contains black background which I do not want please note that original image does not have any black background it is actually white. I am attaching the code for your reference, I am new to opencv and don't have much understanding about it also so kindly help me out.
private void Segmentation() {
Mat srcMat = new Mat();
gray = new Mat();
Utils.bitmapToMat(imageBmp, srcMat);
Imgproc.cvtColor(srcMat, gray, Imgproc.COLOR_RGBA2GRAY);
grayBmp = Bitmap.createBitmap(imageBmp.getWidth(), imageBmp.getHeight(), Bitmap.Config.RGB_565);
Utils.matToBitmap(gray, grayBmp);
grayscaleHistogram();
Mat threshold = new Mat();
Imgproc.threshold(gray, threshold, 0, 255, Imgproc.THRESH_BINARY_INV + Imgproc.THRESH_OTSU);
thresBmp = Bitmap.createBitmap(imageBmp.getWidth(), imageBmp.getHeight(), Bitmap.Config.RGB_565);
Utils.matToBitmap(threshold, thresBmp);
Mat closing = new Mat();
Mat kernel = Mat.ones(5, 5, CvType.CV_8U);
Imgproc.morphologyEx(threshold, closing, Imgproc.MORPH_CLOSE, kernel, new Point(-1, -1), 3);
closingBmp = Bitmap.createBitmap(imageBmp.getWidth(), imageBmp.getHeight(), Bitmap.Config.RGB_565);
Utils.matToBitmap(closing, closingBmp);
result = new Mat();
Core.subtract(closing, gray, result);
Core.subtract(closing, result, result);
resultBmp = Bitmap.createBitmap(imageBmp.getWidth(), imageBmp.getHeight(), Bitmap.Config.RGB_565);
Utils.matToBitmap(result, resultBmp);
Glide.with(ResultActivity.this).asBitmap().load(resultBmp).into(ivAfter);
}
enter image description here
What exactly do you want it to be then? Binary thresholding works like this:
if value < threshold:
value = 0
else:
value = 1
Of course you can convert it to a grayscale / RGB image and adjust the background to your liking. You can also invert your image (white background, black segmentation) by using the ~ operator.
segmented_image = ~ segmented_image
Edit: OpenCV has a dedicated flag to invert the results: CV_THRESH_BINARY_INV You are already using it, maybe try changing it to CV_THRESH_BINARY
I use Android Studio 2.3 version
and I use Opencv 3.2 for Android and android verison of my Phone is 4.4.2
this is some of my source codes.
please attention to case VIEW_MODE_CANNY
#Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
final int viewMode = mViewMode;
switch(viewMode){
case VIEW_MODE_RGBA:
mRgba = inputFrame.rgba();
break;
case VIEW_MODE_GRAY:
Imgproc.cvtColor(inputFrame.gray(), mRgba, Imgproc.COLOR_GRAY2RGBA, 4);
break;
case VIEW_MODE_CANNY:
try{
Imgproc.cvtColor(mRgba, mGray, Imgproc.COLOR_RGBA2GRAY);
Imgproc.GaussianBlur(mGray, mGray, new Size(5, 5), 2, 2);
Imgproc.Canny(mGray, mIntermediateMat, 35, 75);
Imgproc.cvtColor(mIntermediateMat, mRgba, Imgproc.COLOR_GRAY2BGRA, 4);
}catch(Exception e){
Log.i(TAG,e.toString());
e.printStackTrace();
}
break;
}
return mRgba;
}
my application show 3 deferent view. Gray , Color and Canny
Gray and Color are run well.
but if I choose canny It is terminated automatically.
No log and No exception
I can not even guess why not
please give me tips..
It looks to me the error is in this line:
Imgproc.cvtColor(mRgba, mGray, Imgproc.COLOR_RGBA2GRAY);
Should be:
Imgproc.cvtColor(inputFrame.rgba(), mGray, Imgproc.COLOR_RGBA2GRAY);
It crashes because you give an uninitialized input image to cvtColor.
By the way, your VIEW_MODE is a little bit confusing: it's not clear if it refers to the kind of input you get, or the kind of output you want to generate.
I am new in openCV android image Processing. but i am facing some problem. when i use openCV in android and i use Mat then my apps will crushed.... what is the problem with this.....
My code is here..:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView img=(ImageView) findViewById(R.id.imageView);
Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.in);
Mat tmp = new Mat (b.getWidth(), b.getHeight(), CvType.CV_8UC1);
Utils.bitmapToMat(b, tmp);
Imgproc.cvtColor(tmp, tmp, Imgproc.COLOR_RGB2GRAY);
//there could be some processing
Imgproc.cvtColor(tmp, tmp, Imgproc.COLOR_GRAY2RGB, 4);
Utils.matToBitmap(tmp, b);
img.setImageBitmap(b);
}
There are multiple problems:
Mat constructor is Mat(height, width, type), you inverted height and width.
CV_8UC1 is a single channel (grayscale). So if it IS necessary to create the Mat in advance, you should create a Mat with appropriate number of channels. I assume you want to use a RGB image, so use CV_8UC3. But typically, functions re-allocate the Mat if the size doesn't fit. If that's the case with bitmapToMat too, then there is another problem.
Afaik, android uses RGBA as standard color-space. So PROBABLY after Utils.bitmapToMat(b, tmp); tmp is a 4 channel RGBA matrix. So please try Imgproc.cvtColor(tmp, tmp, Imgproc.COLOR_RGBA2GRAY); and later Imgproc.cvtColor(tmp, tmp, Imgproc.COLOR_GRAY2RGBA, 4); if you aren't sure you should add some checks like if Mat.channels isn't 3, don't try to convert RGB2GRAY if the check fails you can try to find out what the real number of channels is and why.
I am building an Android Application and I want to be able to detect black circles. I am using OpenCV3 for Android and I am able to filter out the black colours from my camera feed using the code below. Kindly note that I used the Color-blob-detection example given in the Android SDK and tweaked the code as such:
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba();
if (mIsColorSelected) {
Bitmap resultBitmap;
resultBitmap = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(),Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mRgba, resultBitmap);
//TODO - look for circles
Mat mat = new Mat(resultBitmap.getWidth(), resultBitmap.getHeight(), CvType.CV_8UC1);
Utils.bitmapToMat(resultBitmap, mat);
final Bitmap bitmap;
//TODO - filter out the black only
Mat mHSV = mat;
Mat mHSVThreshed = mat;
Mat mRgba2 = mat;
Imgproc.cvtColor(mat, mHSV, Imgproc.COLOR_BGR2HSV, 0);
Core.inRange(mHSV, new Scalar(0, 0, 0), new Scalar(130, 130, 130), mHSVThreshed);
Imgproc.cvtColor(mHSVThreshed, mat, Imgproc.COLOR_GRAY2BGR, 0);
Imgproc.cvtColor(mat, mRgba2, Imgproc.COLOR_BGR2RGBA, 0);
Imgproc.GaussianBlur(mRgba2, mRgba2, new Size(9, 9), 2, 2);
//this is for displaying purposes only.
//At this point, the image would be black and white, where the white spots are the black detected blobs
// Bitmap bmp = Bitmap.createBitmap(mRgba2.cols(), mRgba2.rows(), Bitmap.Config.ARGB_8888);
//Utils.matToBitmap(mRgba2, bmp);
//bitmap = bmp; //resultBitmap;
//TODO - new circle detection code: this uses the colour filtered Mat
mat = mRgba2;
Imgproc.HoughCircles(mat, circles,
Imgproc.CV_HOUGH_GRADIENT, 1, minDist, 100,
20, 0, 0);
/* get the number of circles detected */
int numberOfCircles = (circles.rows() == 0) ? 0 : circles.cols();
/* draw the circles found on the image */
for (int i = 0; i < numberOfCircles; i++) {
/* get the circle details, circleCoordinates[0, 1, 2] = (x,y,r)
* (x,y) are the coordinates of the circle's center
*/
double[] circleCoordinates = circles.get(0, i);
int x = (int) circleCoordinates[0], y = (int) circleCoordinates[1];
Point center = new Point(x, y);
int radius = (int) circleCoordinates[2];
/* circle's outline */
Imgproc.circle(mRgba2, center, radius, new Scalar(0,
200, 255), 4);
/* circle's center outline */
Imgproc.rectangle(mRgba2, new Point(x - 5, y - 5),
new Point(x + 5, y + 5),
new Scalar(0, 200, 255), -1);
}
Utils.matToBitmap(mRgba2, resultBitmap);
bitmap = resultBitmap;
runOnUiThread(new Runnable() {
#Override
public void run() {
mOpenCvCameraView.disableView();
mOpenCvCameraView.setVisibility(SurfaceView.GONE);
imageView.setVisibility(View.VISIBLE);
imageView.setImageBitmap(bitmap);
}
});
}
return mRgba;
}
What my code does is that it takes a snapshot of the camera feed as a Mat, and then using that Mat, I do some image processing on it and to black out everything except the black colour. The resulting Mat is the mRgba2 variable and I converted to Bitmap and displayed on an ImageView. I displayed this Bitmap to confirm that I am getting the result I want.
After I know that I'm able to filter out the colour I wanted, I then run a GaussianBlur on it then proceed to run HoughCircles. However, when I run the
Imgproc.HoughCircles(mat, circles,
Imgproc.CV_HOUGH_GRADIENT, 1, minDist, 100,
20, 0, 0);
line, I get an
The source image must be 8-bit, single-channel in function CvSeq* cvHoughCircles(CvArr*, void*, int, double, double, double, double, int, int)
Error.
I know that the code wherein I run HoughCircles on a given mat variable works, because I tested it before. Now, changing the mat variable I feed onto it does not, and I wonder what I did differently for the code to not work.
HoughCircles runs only on grayscale (CV8U) images.
Replacing
Imgproc.cvtColor(mat, mRgba2, Imgproc.COLOR_BGR2RGBA, 0);
with
Imgproc.cvtColor(mat, mRgba2, Imgproc.COLOR_BGR2GRAY, 0);
should remove the error.
Then the problem is to detect circles of a given color. This won't pose much of a problem in your case, because you are detecting black circles anyway. Instead of black circles, this will detect dark circles.
If you have dark colors other than black in some of the circles, you can filter them out separately by looking at the pixel values in a different color space.
I'm trying to convert Mat rectangle from onCameraFrame to bitmap then send the bitmap to ocr function because i need to make the ocr works on real-time on ROI according to rectangle. I tried these lines:
Mat mgray= inputFrame.gray();
Mat grayInnerWindow = mgray.submat(100, 100 +500, 150, 200 + 50);
Imgproc.cvtColor(mIntermediateMat, rgbaInnerWindow, Imgproc.COLOR_GRAY2BGRA, 4);
rgbaInnerWindow.release();
Size sizeGray = grayInnerWindow.size();
int rowss = (int) sizeGray.height;
int colss = (int) sizeGray.width;
Mat tmp = new Mat(colss, rowss, CvType.CV_8UC4);
Imgproc.cvtColor(rgbaInnerWindow, tmp, Imgproc.COLOR_RGBA2BGRA, 4);
Bitmap bmp = Bitmap.createBitmap(tmp.cols(), tmp.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(tmp, bmp);
ImageView Img = (ImageView)findViewById(R.id.image_manipulations_activity_surface_view);
Img.setImageBitmap(bmp);
but when i run it terminated.
you are releasing rgbaInnerWindow, then you re-use it as input to cvtColor.
yep, that will burn, rgbaInnerWindow is invalid/empty now..
also, why all those cvtColor calls ? can't you just pass an 8bit grayscale image to your ocr?
(converting a 4channel, all grayscale image from rgba to bgra is utterly useless)