Detecting Objects with Opencv java - java

I am trying to extract contours objects from this:
Which is the S component of a HSV image obtained from this:
My code:
Mat hsvImage = new Mat();
Imgproc.cvtColor(image, hsvImage, Imgproc.COLOR_BGR2HSV);
List<Mat> images = new ArrayList<>();
Core.split(hsvImage, images);
Mat blur = new Mat();
Imgproc.medianBlur(images.get(1), blur, 1);
Mat thresh = new Mat();
Imgproc.threshold(blur, thresh, 40, 255, Imgproc.THRESH_BINARY);
List<MatOfPoint> contours = new ArrayList<>();
Imgproc.findContours(thresh, contours, new Mat(), Imgproc.RETR_LIST,
Imgproc.CHAIN_APPROX_NONE);`
Results are not bad, but I need to improve detection.
I would like to remove image background, but I don't know if is possible and how. Any suggestion would be appreciated.

Related

How can I detect squares using opencv4.2 (Android)

I am detecting a rectangle and comparing the color to a urine test strip.
How can i detect all of squares? I want to detect the remaining squares in the picture below. I have tried changing the brightness and contrast
Here is my code:
MainActivity.java
...
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
...
Bitmap img = BitmapFactory.decodeStream(in);
in.close();
Bitmap changeImg = changeBitmapContrastBrightness(img, (float)1, 10);
Mat cMap = new Mat();
Utils.bitmapToMat(changeImg, cMap);
List<MatOfPoint> squres = processImage(cMap);
for (int i = 0; i < squres.size(); i++) {
setLabel(cMap, String.valueOf(i), squres.get(i));
}
Bitmap resultBitmap = Bitmap.createBitmap(cMap.cols(), cMap.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(cMap, resultBitmap);
imgView.setImageBitmap(resultBitmap);
...
}
...
private static List<MatOfPoint> processImage(Mat img){
ArrayList<MatOfPoint> squares = new ArrayList<>();
Mat matGray = new Mat();
Mat matCny = new Mat();
Mat matBlur = new Mat();
Mat matThresh = new Mat();
Mat close = new Mat();
// 노이즈 제거위해 다운스케일 후 업스케일
// Imgproc.pyrDown(matInit, matBase, matBase.size());
// Imgproc.pyrUp(matBase, matInit, matInit.size());
// GrayScale
Imgproc.cvtColor(img, matGray, Imgproc.COLOR_BGR2GRAY);
// Blur
Imgproc.medianBlur(matGray, matBlur, 5);
// // Canny Edge 검출
// Imgproc.Canny(matBlur, matCny, 0, 255);
// // Binary
Imgproc.threshold(matBlur, matThresh, 160, 255, Imgproc.THRESH_BINARY_INV);
Imgproc.morphologyEx(matThresh, close, Imgproc.MORPH_CLOSE, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3,3)));
// // 노이즈 제거
// Imgproc.erode(matCny, matCny, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new org.opencv.core.Size(6, 6)));
// Imgproc.dilate(matCny, matCny, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new org.opencv.core.Size(12, 12)));
List<MatOfPoint> contours = new ArrayList<>();
Mat hierarchy = new Mat();
Imgproc.findContours(close, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
double min_area = 0;
double max_area = 10000;
for(MatOfPoint cnt : contours){
double contourArea = Imgproc.contourArea(cnt);
if(contourArea > min_area && contourArea < max_area){
squares.add(cnt);
}
}
return squares;
}
App result Image
Original Image
Please help me..
Your code is correctly identifying the smaller boxes and ignoring the very large box which is the strip, so the basics are all in place.
It is not recognising the smaller boxes on the strip - given that your contour finding is clearly working this suggests that the threshold value in your threshold function (160 in your code above) may need to be adjusted so it includes the color boxes on the strip which do not have a black contour. The black contour will be definitely detached.
Whatever the root causes you'll probably find the easiest way to debug it is to output and look at the intermediate images generated - this will allow you check visually yourself very quickly the result of your blurring and thresholding.
You could also take a look at using adaptive thresholding if you are working with multiple images and find the threshold is not something you can reliably determine in advance. The documentation is here: https://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html?highlight=adaptivethreshold and there is a very nice example in this answer here: https://stackoverflow.com/a/31290735/334402
adaptiveThreshold parameters allow you fine tune its behaviour and it is worth experimenting with them see what works best for a given type if image:

Display Keypoints on Image in Android - OpenCV

I'm trying display a image with keypoints detected. In my code, i get a list of key points, my i can't display the image on screen. I think that my problem is on converting the image to bitmap from MAT.
What i'm doing wrong ?
Here is my code:
Mat teste = new Mat();
Mat mRgba = teste.clone();
Mat outputMat = new Mat();
BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable();
Bitmap bitmap = drawable.getBitmap();
Utils.bitmapToMat(bitmap, teste);
MatOfKeyPoint myKeyPoints = new MatOfKeyPoint();
FeatureDetector orb = FeatureDetector.create(FeatureDetector.ORB);
orb.detect(teste, myKeyPoints);
List<KeyPoint> referenceKeypointsList =
myKeyPoints.toList();
Imgproc.cvtColor(teste, mRgba, Imgproc.COLOR_RGBA2RGB,4);
Features2d.drawKeypoints(mRgba, myKeyPoints, mRgba, new Scalar(2,254,255), Features2d.DRAW_RICH_KEYPOINTS);
Imgproc.cvtColor(mRgba, outputMat, Imgproc.COLOR_RGB2RGBA);
Utils.matToBitmap(outputMat, bitmap);
imageView.setImageBitmap(bitmap);
Look my code. It works fine
int whichDescriptor = siftDescriptor; //freakDescriptor;
// Features SEARCH
int detectorType = FeatureDetector.SIFT;
FeatureDetector detector = FeatureDetector.create(detectorType);
Mat mask = new Mat();
MatOfKeyPoint keypoints = new MatOfKeyPoint();
detector.detect(image, keypoints , mask);
if (!detector.empty()){
// Draw kewpoints
Mat outputImage = new Mat();
Scalar color = new Scalar(0, 0, 255); // BGR
int flags = Features2d.DRAW_RICH_KEYPOINTS; // For each keypoint, the circle around keypoint with keypoint size and orientation will be drawn.
Features2d.drawKeypoints(image, keypoints, outputImage, color , flags);
displayImage(Mat2BufferedImage(outputImage), "Feautures_"+detectorType);
}
displayImage() and Mat2BufferedImage() are referenced here
link1
or link2

SVM prediction of images OpenCV

I'm able to train the system but when I try to predict, Bad argument exception is raised.
OpenCV Error: Bad argument (The sample is not a valid vector) in cvPreparePredictData, file ........\opencv\modules\ml\src\inner_functions.cpp, line 1099
Exception in thread "main" CvException [org.opencv.core.CvException: cv::Exception: ........\opencv\modules\ml\src\inner_functions.cpp:1099: error: (-5) The sample is not a valid vector in function cvPreparePredictData
]
This is my code:
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat classes = new Mat();
Mat trainingData = new Mat();
Mat trainingImages = new Mat();
Mat trainingLabels = new Mat();
CvSVM clasificador;
String path="C:\\java workspace\\ora\\images\\Color_Happy_jpg";
for (File file : new File(path).listFiles()) {
Mat img=new Mat();
Mat con = Highgui.imread(path+"\\"+file.getName(),Highgui.CV_LOAD_IMAGE_GRAYSCALE);
con.convertTo(img, CvType.CV_32FC1,1.0/255.0);
img.reshape(1, 1);
trainingImages.push_back(img);
trainingLabels.push_back(Mat.ones(new Size(1, 75), CvType.CV_32FC1));
}
System.out.println("divide");
path="C:\\java workspace\\ora\\images\\Color_Sad_jpg";
for (File file : new File(path).listFiles()) {
Mat img=new Mat();
Mat m=new Mat(new Size(640,480),CvType.CV_32FC1);
Mat con = Highgui.imread(file.getAbsolutePath(),Highgui.CV_LOAD_IMAGE_GRAYSCALE);
con.convertTo(img, CvType.CV_32FC1,1.0/255.0);
img.reshape(1, 1);
trainingImages.push_back(img);
trainingLabels.push_back(Mat.zeros(new Size(1, 75), CvType.CV_32FC1));
}
trainingLabels.copyTo(classes);
CvSVMParams params = new CvSVMParams();
params.set_kernel_type(CvSVM.LINEAR);
CvType.typeToString(trainingImages.type());
CvSVM svm=new CvSVM();
clasificador = new CvSVM(trainingImages,classes, new Mat(), new Mat(), params);
clasificador.save("C:\\java workspace\\ora\\images\\svm.xml");
Mat out=new Mat();
clasificador.load("C:\\java workspace\\ora\\images\\svm.xml");
Mat sample=Highgui.imread("C:\\java workspace\\ora\\images\\Color_Sad_jpg\\EMBfemale20-2happy.jpg",Highgui.CV_LOAD_IMAGE_GRAYSCALE);
sample.convertTo(out, CvType.CV_32FC1,1.0/255.0);
out.reshape(1, 75);
System.out.println(clasificador.predict(out));
1.
your trainLabels are still wrong.
you need a float mat with numrows==numimages and 1 col. so, 1 label per image.
so your sad faces should have :
trainingLabels.push_back(-1.0);
and your happy ones should have :
trainingLabels.push_back(1.0);
2.
the sample for the prediction has to be processed in the same way as for the training.
sample.convertTo(out, CvType.CV_32FC1,1.0/255.0);
out.reshape(1, 1);

How to resize an image in Java with OpenCV?

After cropping an image how can I resize it?
Mat croppedimage = cropImage( image, rect );
Mat resizeimage = croppedimage.resize( any dimension ); //need to change this line
I think, you want this.
e.g.
Mat croppedimage = cropImage(image,rect);
Mat resizeimage = new Mat();
Size sz = new Size(100,100);
Imgproc.resize( croppedimage, resizeimage, sz );
If you want to scale an image using OpenCV java then do the following:
import static org.opencv.imgproc.Imgproc.*;
import static org.opencv.imgcodecs.Imgcodecs.imread;
Main code:
Mat src = imread("imageName.jpg");
Mat resizeimage = new Mat();
Size scaleSize = new Size(300,200);
resize(src, resizeimage, scaleSize , 0, 0, INTER_AREA);
For downscaling it is recommended to use: INTER_AREA and for upscaling use INTER_CUBIC
For more details: OpenCV Ref for Resize
Please read manual for c++ method Resize it's the same to java.
You can choose a type of interpolation. In some cases it's important for a best result.
Mat croppedImage = cropImage(image,rect);
Mat resizeImage = new Mat(anyHeight, anyWidth, croppedImage.type());
int interpolation = Imgproc.INTER_CUBIC;
Imgproc.resize(croppedImage, resizeImage, resizeImage.size(), 0, 0, interpolation );

Watershed in Opencv Android

I was trying to implement watershed function from OpenCV on Android. However my program always crashed at the place where watershed function is called. I can output the marker's result perfectly fine. But the watershed function always just crashes. Here is my code:
Mat threeChannel = new Mat();
Imgproc.cvtColor(mRgba, threeChannel, Imgproc.COLOR_BGR2GRAY);
Imgproc.threshold(threeChannel, threeChannel, 100, 255, Imgproc.THRESH_BINARY);
Mat fg = new Mat(mRgba.size(),CvType.CV_8U);
Imgproc.erode(threeChannel,fg,new Mat(),new Point(-1,-1),2);
Mat bg = new Mat(mRgba.size(),CvType.CV_8U);
Imgproc.dilate(threeChannel,bg,new Mat(),new Point(-1,-1),3);
Imgproc.threshold(bg,bg,1, 128,Imgproc.THRESH_BINARY_INV);
Mat markers = new Mat(mRgba.size(),CvType.CV_8U, new Scalar(0));
Core.add(fg, bg, markers);
WatershedSegmenter segmenter = new WatershedSegmenter();
segmenter.setMarkers(markers);
Mat result = segmenter.process(mRgba);
return result;
WatershedSegmenter calss is as follows:
public class WatershedSegmenter{
public Mat markers;
public void setMarkers(Mat markerImage)
{
markerImage.convertTo(markers, CvType.CV_32S);
}
public Mat process(Mat image)
{
Imgproc.watershed(image, markers);
markers.convertTo(markers,CvType.CV_8U);
return markers;
}
}
Has anybody managed to get this working on Android before? I managed to get it to work in C++ with Qt before following this tutorial: link. However I haven't got any luck on Android at the moment.
I found out the reason of crash now. watershed is taking a 8 bit 3 channel format of data, and RGBA is a 4 channel data. I just convert it from RGBA to RGB, and it solved all the issues.
Your Mat doesn't match the correct .depth() and/or .channel().
The first step is to double-check each Mat has the type you think it does by using the myMat.depth() and myMat.channels() functions. The function watershed uses two Mat arguments. The first should be an 8-bit, 3-channel image, and the second should be a 32-bit single-channel image.
If they are not the right kind of image, use cvtColor to convert from what you have to what you need.
Try out this solution
BitmapFactory.Options o = new BitmapFactory.Options();
o.inDither = false;
o.inSampleSize=4;
int width , height ;
width = src_Bitmap.getWidth();
height = src_Bitmap.getHeight();
Mat rgba = new Mat();
Mat gray_mat= new Mat();
Mat threeChannel = new Mat();
Utils.bitmapToMat(src_Bitmap,gray_mat);
Imgproc.cvtColor(gray_mat,rgba , Imgproc.COLOR_RGBA2RGB);
Imgproc.cvtColor(rgba, threeChannel, Imgproc.COLOR_RGB2GRAY);
Imgproc.threshold(threeChannel, threeChannel, 100, 255, Imgproc.THRESH_OTSU);
Mat fg = new Mat(rgba.size(),CvType.CV_8U);
Imgproc.erode(threeChannel,fg,new Mat(),new Point(-1,-1),2);
Mat bg = new Mat(rgba.size(),CvType.CV_8U);
Imgproc.dilate(threeChannel,bg,new Mat(),new Point(-1,-1),3);
Imgproc.threshold(bg,bg,1, 128,Imgproc.THRESH_BINARY_INV);
Mat markers = new Mat(rgba.size(),CvType.CV_8U, new Scalar(0));
Core.add(fg, bg, markers);
// Start the WaterShed Segmentation :
Mat marker_tempo = new Mat();
markers.convertTo(marker_tempo, CvType.CV_32S);
Imgproc.watershed(rgba, marker_tempo);
marker_tempo.convertTo(markers,CvType.CV_8U);
result_Bitmap=Bitmap.createBitmap(width,height,Bitmap.Config.RGB_565);
Imgproc.applyColorMap( markers, markers,4 );
Utils.matToBitmap( markers,result_Bitmap);
myImageView.setImageBitmap(result_Bitmap);

Categories

Resources