adaptivethreshold gives an error (opencv, java) - java

I am trying to do adaptiveThresholding on an image but it gives me this error:
OpenCV Error: Assertion failed (src.type() == CV_8UC1) in adaptiveThreshold
I can't seem to understand why, here is my code:
Mat source = Highgui.imread("camera.jpg",
Highgui.CV_LOAD_IMAGE_COLOR);
Mat destination = new Mat(source.rows(),source.cols(),source.type());
Imgproc.cvtColor(source, destination, Imgproc.COLOR_RGB2GRAY);
Highgui.imwrite("grayscale.jpg", destination);
Mat source2 = Highgui.imread("grayscale.jpg",
Highgui.CV_LOAD_IMAGE_COLOR);
Mat destination2 = new Mat(source.rows(),source.cols(),source.type());
Imgproc.adaptiveThreshold(source2, destination2, 255,
Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY_INV, 15, 4);

For adaptiveThreshold source should be 8-bit single-channel image, but you are loading source2 as colour,
So, Change the line
Mat source2 = Highgui.imread("grayscale.jpg", Highgui.CV_LOAD_IMAGE_COLOR);
to
Mat source2 = Highgui.imread("grayscale.jpg", Highgui.CV_LOAD_IMAGE_GRAYSCALE);
Also why to save and load destination image before adaptiveThreshold, pass it directly to adaptiveThreshold()

Related

OpenCV convert Python code to Java

I have the following Python code:
ret,thresh = cv2.threshold(gray,5,255,cv2.THRESH_TOZERO)
kernel1 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(11,11))
kernel2 = np.ones((3,3),np.uint8)
erosion = cv2.erode(thresh,kernel2,iterations = 1)
dilation = cv2.dilate(erosion,kernel1,iterations = 7)
I'm trying to convert it to Java. This is my current version:
double thresh = Imgproc.threshold(gray, gray, 5, 255, Imgproc.THRESH_TOZERO);
Mat kernel1 = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(11, 11));
Mat kernel2 = Mat.ones(3, 3, CvType.CV_8U);
Mat erosion = new Mat();
Imgproc.erode(gray, erosion, kernel2);
Mat dilation = new Mat();
Imgproc.dilate(erosion, dilation, kernel1);
Right now I'm unable to find a place where thresh parameter should be applied and also I'm not using the iterations parameter for Imgproc.erode and Imgproc.dilate methods because the method signature in this case also requires additional Point anchor parameter which I do not have right now.
How to properly convert this code to Java?
UPDATED
I do the following translation:
Mat erosion = new Mat();
Imgproc.erode(gray, erosion, kernel2, new Point(), 1);
Mat dilation = new Mat();
Imgproc.dilate(erosion, dilation, kernel1, new Point(), 7);
and looks like it is working as expected but I'm not sure about new Point() Is it a correct translation?
Here are the dilate declarations in C++/Python/Java:
C++: void dilate(InputArray src, OutputArray dst, InputArray kernel,
Point anchor=Point(-1,-1),
int iterations=1,
int borderType=BORDER_CONSTANT,
const Scalar& borderValue=morphologyDefaultBorderValue() )
Python: cv2.dilate(src, kernel[, dst
[, anchor[, iterations[, borderType[, borderValue]]]]]) → dst
Java: static void dilate(Mat src, Mat dst, Mat kernel, Point anchor, int iterations)
Because there is no default value for anchor if you want to use the param iterations. So pass new Point(-1,-1) is a better choice.
Imgproc.dilate(src, dst, kernel, new Point(-1,-1), iterations);

Replicate Gimp Unsharp Mask with Java - OpenCv

I'm trying to replicate unsharp mask in Gimp with using Java and OpenCv. I use a grayscale image as input and apply unsharp mask, but results are not even close.
I try to implement this C++ code:
Mat blurred; double sigma = 1, threshold = 5, amount = 1;
GaussianBlur(img, blurred, Size(), sigma, sigma);
Mat lowContrastMask = abs(img - blurred) < threshold;
Mat sharpened = img*(1+amount) + blurred*(-amount);
img.copyTo(sharpened, lowContrastMask);
And this is my Java implementation:
double sigma = 1, threshold = 5, amount = 1;
Mat source = Imgcodecs.imread(input.getName());
Mat destination = new Mat();
Imgproc.GaussianBlur(source, destination, new Size(), sigma, sigma);
Mat lowContrastMask = new Mat();
Core.absdiff(source, destination, lowContrastMask);
Imgproc.threshold(lowContrastMask, lowContrastMask, 0, threshold, Imgproc.THRESH_BINARY);
Mat sharpened = new Mat();
Core.multiply(source, new Scalar(0), sharpened, amount+1);
Mat sharpened2 = new Mat();
Core.multiply(destination, new Scalar(0), sharpened2, -amount);
Core.add(sharpened2, sharpened, sharpened);
source.copyTo(sharpened, lowContrastMask);
Alternative Unsharp Masking method:
Mat source = Imgcodecs.imread(input.getName());
Mat destination = new Mat();
Imgproc.GaussianBlur(source, destination, new Size(0,0), 60);
Core.addWeighted(source, 1.5, destination, -1, 0, destination);
So, both methods are working but results are and not good as gimp result. I'm open to any suggestion. I know it look like a bad implementation. I'm a newbie, I appreciate any help.

Loading image from file as given "type" into an OpenCV Mat?

I recently started working with the Java bindings for OpenCV to make a quick and dirty project to do template matching. Basically I am trying to read a set of jpg images (saved in MS Paint) into Mats and then use template matching to find their locations from a screen shot taken with Java.Robot.
When it comes time to do the template matching this error is thrown
OpenCV Error: Assertion failed ((depth == CV_8U || depth == CV_32F)
&& type == _templ.type() && _img.dims() <= 2) in cv::matchTemplate
After searching it looks like the issue is that the two Mats I am trying to use do not have the same "type". What I am not sure of is what this refers to. I assume it is the Mats CvType, if I print out the CvType of the image and template I get a type() of 4 == CvType.CV_32SC1 for my template I get a type() of 20 == CvType.CV_32SC3.
But I feel like this is not the correct type() I am trying to compare, I have feeling it refers to the data type of how the data is stored in the Mat? But I have no good links to back this up just remembrances from many SO searches.
Here is my code for loading in my jpg images into a Mat
Mat pic_ = Imgcodecs.imread("MyPath\\image.jpg");
pic_.convertTo(pic_, CvType.CV_32SC1);
Here the second line turns my type() from 20 to 16, though as per my last comment I don't think this is the proper way to alter the Mat to match the image?... Because convertTo'ing this Mat to match the type of the screen shot `(below) does not fix the error?
Here is how I am creating the image Mat
Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage screenShot = rob.createScreenCapture(screenRect);
Mat screenImage = bufferedImageToMat(screenShot);
So I first take a screenshot with Java.Robot.createScreenCapture I then convert it to a Mat with
private Mat bufferedImageToMat(BufferedImage inBuffImg)
{
BufferedImage image = new BufferedImage(inBuffImg.getWidth(), inBuffImg.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d= image.createGraphics();
g2d.drawImage(inBuffImg, 0, 0, null);
g2d.dispose();
Mat mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_32SC1);
int[] data = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
mat.put(0, 0, data);
return mat;
}
From what I could tell the BufferedImage created by Robot is of type BufferedImage.TYPE_3BYTE_BGR which gives me an error "DataBufferInt cannot be cast to DataBufferByte" when trying to get the pixel data. So per the linked question I redraw the BufferedImage as type BufferedImage.TYPE_INT_RGB and pull out the data as a DataBufferInt.
So in all, should I be trying to match the Mat.type() or does my problem lie elsewhere? If not elsewhere how can I alter either of the Mats so that they can be used with Imgproc.matchTemplate properly?
I feel like the easiest solution would be to convert the image loaded from file to match the screenshot Mat?
EDIT: The exact section of code that gives the error is below
// Mat imageTemplate is a function argument; the loaded jpg image
// Take a picture of the screen
Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage screenShot = rob.createScreenCapture(screenRect);
Mat screenImage = bufferedImageToMat(screenShot);
// Create the result matrix
int result_cols = screenImage.cols() - imageTemplate.cols() + 1;
int result_rows = screenImage.rows() - imageTemplate.rows() + 1;
Mat result = new Mat(result_rows, result_cols, CvType.CV_32SC1);
newStatus("ScreenType: " + screenImage.type());
newStatus("TemplaType: " + imageTemplate.type());
// Choose a matching method
int matchMethod = Imgproc.TM_SQDIFF_NORMED;
// Do the Matching and Normalize
Imgproc.matchTemplate(screenImage, imageTemplate, result, matchMethod);
// Error occurs on previous line
As #Miki pointed out in the comments the answer was getting the channe type to match for the image and template. I ended up changing my bufferedImageToMat function.
private Mat bufferedImageToMat(BufferedImage inBuffImg)
{
BufferedImage image = new BufferedImage(inBuffImg.getWidth(), inBuffImg.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2d= image.createGraphics();
g2d.drawImage(inBuffImg, 0, 0, null);
g2d.dispose();
Mat mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC3);
byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
mat.put(0, 0, data);
return mat;
}
My templates are read in as CvType.CV_8UC3, so it was just a matter of creating a Mat from the screen image with this type!

Training SVM bad argument error

I followed the code in How to train an SVM with opencv based on a set of images? and I get the following exception
OpenCV Error: Bad argument (train data must be floating-point matrix) in cvCheckTrainData, file ......\src\opencv\modules\ml\src\inner_functions.cpp, line 857
Exception in thread "main" CvException [org.opencv.core.CvException: ......\src\opencv\modules\ml\src\inner_functions.cpp:857: error: (-5) train data must be floating-point matrix in function cvCheckTrainData
]
I followed the steps as mentioned in the comment. But still in vain.
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());
con.convertTo(img, CvType.CV_32F,1.0/255.0);
img.reshape(1, 1);
trainingImages.push_back(img);
trainingLabels.push_back(Mat.ones(new Size(1, 1), CvType.CV_32F));
}
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_32FC3);
Mat con = Highgui.imread(file.getAbsolutePath());
con.convertTo(img, CvType.CV_32F,1.0/255.0);
img.reshape(1, 1);
trainingImages.push_back(img);
System.out.println((CvType.typeToString(img.type())));
trainingLabels.push_back(Mat.zeros(new Size(1, 1), CvType.CV_32F));
}
trainingLabels.copyTo(classes);
CvSVMParams params = new CvSVMParams();
params.set_kernel_type(CvSVM.LINEAR);
System.out.println(CvType.typeToString(trainingImages.type()));
CvSVM svm=new CvSVM();
System.out.println(svm.get_support_vector_count());
boolean b=svm.train(trainingImages, classes);
System.out.print(b);
}
}

OpenCV Error: Assertion failed (scn == 3 || scn == 4) while using Watershed in OpenCV android sdk

I am working on an Android application that used the OpenCV-2.4.8 android sdk.
The following sample code tries to detect an object using the Watershed segmenter algorithm of the OpenCV library.
//bmp is the source bitmap that I am reading from a Drawable resource.
Mat mBackgroundMat = new Mat(new Size(bmp.getWidth(), bmp.getHeight()), CvType.CV_8UC3);
Utils.bitmapToMat(bmp, mBackgroundMat);
//Initialize the Mat Objects
Mat backgroundMat = new Mat();
Mat greyMatImg = new Mat();
Mat thresholdImg = new Mat();
Mat markerImg = new Mat();
//Erode and dillate
Imgproc.erode(mBackgroundMat, backgroundMat, new Mat(), new Point(-1, -1), 12);
Imgproc.dilate(backgroundMat, backgroundMat, new Mat(), new Point(-1, -1), 12);
// Imgproc.cvtColor(backgroundMat, backgroundMat, Imgproc.COLOR_RGB2BGR);
Imgproc.cvtColor(backgroundMat, greyMatImg, Imgproc.COLOR_BGR2GRAY);
Imgproc.threshold(greyMatImg, thresholdImg, 0, 255, Imgproc.THRESH_BINARY_INV);
Imgproc.distanceTransform(thresholdImg, markerImg, Imgproc.CV_DIST_L2, Imgproc.CV_DIST_MASK_5);
Imgproc.cvtColor(thresholdImg, thresholdImg, Imgproc.COLOR_GRAY2BGR, 3);
Mat tempMat = new Mat(markerImg.rows(), markerImg.cols(), CvType.CV_32SC1);
Imgproc.cvtColor(markerImg, tempMat, CvType.CV_32SC1, 0);
Imgproc.watershed(thresholdImg, tempMat);
//Release unused mats.
tempMat.release();
backgroundMat.release();
greyMatImg.release();
markerImg.release();
//Output thresholdImg
I am getting the following error:
cv::error()(2566): OpenCV Error: Assertion failed (scn == 3 || scn == 4) in void cv::cvtColor(InputArray, OutputArray, int, int), file /home/reports/ci/slave_desktop/50-SDK/opencv/modules/imgproc/src/color.cpp, line 3648
Please help me in figuring out what I am doing wrong here.
Imgproc.cvtColor(markerImg, tempMat, CvType.CV_32SC1, 0);
I think it is this line - opencv is complaining about markerImg not being a 3 or 4 channel image. It looks like the Mats in this call have the same number of channels so perhaps you just need to convert between data types; the result of distanceTransform seems to give a CV_32FC1 so you could try just converting like this:
markerImg.convertTo(tempMat, CvType.CV_32SC1);
I had a similar error...
In my case, the error was because the Mat didn't have data.
Try to do this validation:
`if(!src.data) //where src is the Mat with the image
{
Log.d("Error","Adios");
exit(0);
}`
If you don't have data in src, then you won't convert this to Bitmap

Categories