I am writing function to find rectangles in Mat. But i am getting exception at mixChannels()function. My code is as follow. Can some one check and tell me what could be wrong in it ?I would also like to know how i can implement gray = gray0 >= (l+1)*255/N; in java or android ?
private void findSqaures(Mat sourceImage){
Vector<Point> sqares;
Mat pyr,timing ,gry =new Mat();
pyr=new Mat(sourceImage.size(),CvType.CV_8U);
timing=new Mat(sourceImage.size(),CvType.CV_8U);
int thresh = 50, N = 11;
List<Mat> grayO=new ArrayList<Mat>();
List<Mat> timing1=new ArrayList<Mat>();
Imgproc.pyrDown(sourceImage, pyr,new Size(sourceImage.cols()/2.0, sourceImage.rows()/2));
Imgproc.pyrUp(pyr, timing,sourceImage.size());
// Vector<Point> contours=new Vector<Point>();
timing1.add(0,pyr);
grayO.add(0,timing);
// grayO.add(0,timing);
for(int c=0;c<3;c++){
int ch[]={1,0};
MatOfInt fromto = new MatOfInt(ch);
Core.mixChannels(timing1, grayO, fromto); // Getting Exception here
// Core.mixChannels(src, dst, fromTo)
for(int i=0;i<N;i++){
Mat output=grayO.get(0);
if(i==0){
Imgproc.Canny(output, gry, 5, thresh);
Imgproc.dilate(gry, gry, new Mat(), new Point(-1,-1), 1);
}
else {
// output = output >= (i+1)*255/N;
}
// sourceImage=gry;
contours=new ArrayList<MatOfPoint>();
Imgproc.findContours(gry, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
MatOfPoint2f approxCurve = new MatOfPoint2f();
mDrawnContours.clear();
Log.i(TAG, "::findSqaures:" + "contours.size():"+contours.size());
for(int j=0;i<contours.size();j++){
MatOfPoint tempContour=contours.get(i);
MatOfPoint2f newMat = new MatOfPoint2f( tempContour.toArray() );
int contourSize = (int)tempContour.total();
Imgproc.approxPolyDP(newMat, approxCurve, contourSize*0.02, true);
MatOfPoint points=new MatOfPoint(approxCurve.toArray());
// if( approx.size() == 4 && fabs(contourArea(cv::Mat(approx))) > 1000 && cv::isContourConvex(cv::Mat(approx))) {
if(points.toArray().length==4 && (Math.abs(approxCurve.total())>1000) && Imgproc.isContourConvex(points)){
double maxCosine=0;
int k;
for( k=2;k<5;k++){
double cosine=Math.abs(angle(points.toArray()[k%4], points.toArray()[k-2], points.toArray()[k-1]));
if(maxCosine>cosine){
maxCosine=cosine;
}
}
Log.i(TAG, "::findSqaures:" + "maxCosine:"+maxCosine);
if(maxCosine<0.3){
DrawnContours drawnContours=new DrawnContours();
drawnContours.setIndex(k);
mDrawnContours.add(drawnContours);
}
}
}
Log.i(TAG, "::findSqaures:" + "mDrawnContours.size():"+mDrawnContours.size());
}
}
// Core.mixChannels(src, dst, fromTo)
}
The exception is *CvException [org.opencv.core.CvException: /home/reports/ci/slave_desktop/50-SDK/opencv/modules/core/src/matrix.cpp:3210: error: (-215) A.size == arrays[i0]->size in function void cv::NAryMatIterator::init(const cv::Mat, cv::Mat*, uchar*, int)**
Instead of the following
timing1.add(0,pyr);
grayO.add(0,timing);
Try this
timing1.add(pyr);
grayO.add(timing);
Instead of the below line
gry = output >= (i+1)*255/N;
You could use
Imgproc.threshold(output, gry, (l+1) * 255 / N, 255, Imgproc.THRESH_BINARY);
Also instead of using the pyr as the source, blur the image using medianBlur function, you would get better rectangle identification.
From
Core.mixChannels(timing1, grayO, fromto);
element of gray0 array and timing1 array should have the same size.
but pyr has half the size of timing so you've got an error.
Look again at the sample squares.cpp
source of mixChannels function should be the result Mat of pyrUp function
destination of mixChannels function should be a new empty Mat with the same size.
So, correct it with :
timing1.add(0,timing); // or timing1.add(timing)
grayO.add(0, new Mat(timing.size(), timing.type()) );
Regards,
Louis
Related
I am trying to extract a table row containing a filled rectangle in an image file using openCV. I have used findcontours and boundingrect. Disclaimer: I am completely new to opencv and image processing, so this might not be an optimal solution.
This is what I have done so far, it is getting me all the tables in the image including the row i want. How can i filter to just that row?
Imgcodecs imageCodecs = new Imgcodecs();
Mat sourceMat = imageCodecs.imread("image.png");
Mat grayMat = imageCodecs.imread("image.png");
Mat threshold = imageCodecs.imread("image.png");
Mat threshold1 = imageCodecs.imread("image.png");
Imgproc.cvtColor(sourceMat, grayMat, Imgproc.COLOR_BGR2GRAY);
Imgproc.threshold(grayMat, threshold, 70, 255, Imgproc.THRESH_BINARY_INV);
Imgproc.threshold(grayMat, threshold1, 270, 255, Imgproc.THRESH_BINARY);
Core.bitwise_not(grayMat, threshold);
Imgcodecs imgcodecs1 = new Imgcodecs();
imgcodecs1.imwrite("imagethreshold.png", threshold);
List<MatOfPoint> whiteContours = new ArrayList<>();
MatOfPoint heirarchy = new MatOfPoint();
Imgproc.findContours(threshold.clone(), whiteContours, heirarchy, Imgproc.RETR_CCOMP, Imgproc.CHAIN_APPROX_SIMPLE);
int count = 0;
// find appropriate bounding rectangles
for (int i = 0; i < whiteContours.size(); i++) {
RotatedRect boundingRect = Imgproc.minAreaRect(new MatOfPoint2f(whiteContours.get(i).toArray()));
Point rotated_rect_points[] = new Point[4];
boundingRect.points(rotated_rect_points);
Rect rect = Imgproc.boundingRect(new MatOfPoint(rotated_rect_points));
Mat roiMat = sourceMat.submat(rect);
if (rect.area()>15000 && heirarchy.get(0,i) != null) {
// checking if heirarchy has parent, next or previous contour is -1
if(heirarchy.get(0,i)[3]!=-1 && heirarchy.get(0,i)[0] !=-1 && heirarchy.get(0,i)[1] ==-1){
// write to image file
Imgcodecs imgcodecs = new Imgcodecs();
imgcodecs.imwrite("image" + count + ".png", roiMat);
count++;
}
}
}```
I have to do develop a similar algorithm as in Remove top section of image above border line to detect text document, but in Java 1.8 using JavaCV.
The method signature in Python is
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
However in Java it appears to be:
MatVector mt = new MatVector();
findContours(dst, mt, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
I'm stuck into finding the contours and sorting them from biggest to lowest. How do I go about sorting from biggest to lower contours?
My code:
Mat image = imread(imagePath);
Mat gray = new Mat();
cvtColor(mat, gray, COLOR_BGR2GRAY);
Mat grayImg = convertToGray(mat);
GaussianBlur(grayImg, grayImg, new Size(3, 3), 0);
Mat dst = new Mat();
threshold(grayImg, dst, 0, 255,THRESH_BINARY + THRESH_OTSU);
// Find contours and sort for largest contour
MatVector mt = new MatVector();
findContours(dst, mt, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
How to access contours suggestion from https://github.com/bytedeco/javacv/issues/1270:
// accessing contours
MatVector contours = ...
for (int i = 0; i < contours.size(); ++i) {
IntIndexer points = contours.get(i).createIndexer();
int size = (int) points.size(0); // points are stored in a Mat with a single column and multiple rows, since size(0), each element has two channels - for x and y - so the type is CV_32SC2 for integer points
for (int j = 0; j < size; ++j) {
int x = points.get(2 * j);
int y = points.get(2 * j + 1);
// do something with x and y
}
}
Thank you
As #fmw42 said, I refactored the code to look into the contourArea().
See below,
Mat mask = new Mat();
Mat gray = new Mat();
Mat denoised = new Mat();
Mat bin = new Mat();
Mat hierarchy = new Mat();
MatVector contours = new MatVector();
cvtColor(mat, gray, COLOR_BGR2GRAY);
//Normalize
GaussianBlur(gray, denoised, new Size(5, 5), 0);
threshold(denoised, mask, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
normalize(gray, gray, 0, 255, NORM_MINMAX, -1, mask);
// Convert image to binary
threshold(gray, bin, 150, 255, THRESH_BINARY);
// Find contours
findContours(bin, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE);
long contourCount = contours.size();
System.out.println("Countour count " + contourCount);
double maxArea = 0;
int maxAreaId = 0;
for (int i = 0; i < contourCount; ++i) {
// Calculate the area of each contour
Mat contour = contours.get(i);
double area = contourArea(contour);
if(area > maxArea){
maxAreaId = i;
maxArea = area;
}
}
I am trying to make an automatic perspective correction of quadrangle objects.
I am getting error when I am using getPerspectiveTransform function:
OpenCV Error: Assertion failed (src.checkVector(2, CV_32F) == 4 && dst.checkVector(2, CV_32F) == 4) in cv::getPerspectiveTransform
Here is my code:
Mat originalMat = new Mat();
originalMat=Imgcodecs.imread("photo.jpg");
Mat binaryMat = new Mat();
Imgproc.cvtColor(originalMat, binaryMat, Imgproc.COLOR_BGR2GRAY);
Imgproc.threshold(binaryMat, binaryMat, 0 , 255, Imgproc.THRESH_OTSU | Imgproc.THRESH_BINARY);
List<MatOfPoint> contours = new ArrayList<>();
Imgproc.findContours(binaryMat.clone(), contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
int largestContour=0, tempContour, largestContourIndex=0;
if(contours.size()>1)
for (int i = 0; i < contours.size(); i++) {
MatOfPoint2f mop2f = new MatOfPoint2f();
contours.get(i).convertTo(mop2f, CvType.CV_32F);
RotatedRect rect = Imgproc.minAreaRect(mop2f);
tempContour = rect.boundingRect().width * rect.boundingRect().height;
if(largestContour < tempContour){
largestContour = tempContour;
largestContourIndex = i;
}
}
Rect rectangle = Imgproc.boundingRect(contours.get(largestContourIndex));
Point[] boundingRectPoints = new Point[4];
boundingRectPoints[0] = new Point(rectangle.x,rectangle.y);
boundingRectPoints[1] = new Point((rectangle.x+rectangle.width),rectangle.y);
boundingRectPoints[2] = new Point(rectangle.x+rectangle.width,rectangle.y+rectangle.height);
boundingRectPoints[3] = new Point(rectangle.x,rectangle.y+rectangle.height);
MatOfPoint boundingRTMatOfPoint = new MatOfPoint(boundingRectPoints);
Mat beforeCorrectionMat = new Mat();
Mat afterCorrectionMat = new Mat();
contours.get(largestContourIndex).convertTo(beforeCorrectionMat, CvType.CV_32FC2);
boundingRTMatOfPoint.convertTo(afterCorrectionMat, CvType.CV_32FC2);
Mat transmtx = Imgproc.getPerspectiveTransform( beforeCorrectionMat, afterCorrectionMat);
Mat transformed = Mat.zeros(originalMat.height(), originalMat.width(), CvType.CV_8UC1);
Imgproc.warpPerspective(originalMat, transformed, transmtx, originalMat.size());
I found similar question here: Assertion failed when I'm trying to use getPerspectiveTransform on Android-NDK to transform a perspective image
But it doesn't help me.
I would be very grateful for any help.
This means that you need to type float in the code and wherever you want to use float, you must convert it to int. This error indicates that you must use the value of float in your code.
u should use float in getPerspectiveTransform
I want to use the imgradient() function of matlab in my android application using opencv. how can i do so and which function of opencv is equivalent to to Matlab imgradient() function.
i m using below mentioned function is it right ?
public Mat imgradient(Mat grayScaleImage)
{
Mat grad_x=new Mat();
Mat grad_y = new Mat();
Mat abs_grad_x=new Mat();
Mat abs_grad_y=new Mat();
Mat gradientImag = new Mat(grayScaleImage.rows(),grayScaleImage.cols(),CvType.CV_8UC1);
Imgproc.Sobel(grayScaleImage, grad_x, CvType.CV_16S, 1, 0,3,1,0,Imgproc.BORDER_DEFAULT );
Core.convertScaleAbs( grad_x, abs_grad_x );
Imgproc.Sobel( grayScaleImage, grad_y, CvType.CV_16S, 0, 1, 3, 1,0,Imgproc.BORDER_DEFAULT );
Core.convertScaleAbs( grad_y, abs_grad_y );
double[] buff_grad = new double[1];
for(int i = 0; i < abs_grad_y.cols(); i++)
{
for(int j =0 ; j<abs_grad_y.rows() ; j++)
{
double[] buff_x = abs_grad_x.get(j, i);
double[] buff_y = abs_grad_y.get(j, i);
double x = buff_x[0];
double y = buff_y[0];
double ans=0;
try
{
ans = Math.sqrt(Math.pow(x,2)+Math.pow(y,2));
}catch(NullPointerException e)
{
ans = 0;
}
buff_grad[0] = ans;
gradientImag.put(j, i, buff_grad);
}
}
return gradientImag;
}
Have you tried using something like sobel or canny operators?
As matlab imgradient() returns the gradient "magnitude" (i.e. sqrt(dx(x,y)² + dy(x,y)²) for each pixel with coordinates x,y), you may want to do something like:
// 1) Get the horizontal gradient
Mat kH = (cv::Mat_<double>(1,3) << -1,0,1); // differential kernel in x
Mat Dx;
filter2D(image, Dx, -1, kH, cv::Point(-1,-1), 0);
// 2) Get the vertical gradient
Mat kV = (cv::Mat_<double>(3,1) << -1,0,1); // differential kernel in y
Mat Dy;
filter2D(image, Dy, -1, kV, cv::Point(-1,-1), 0);
// 3) Get sqrt(dx²+dy²) in each point
for(int i=0; i<Dx.rows; i++)
for(int j=0; j<Dx.cols; j++)
Dmag.at<double>(i,j) = sqrt(pow(Dx.at<double>(i,j),2)+pow(Dy.at<double>(i,j),2));
It should get you what you you want. You can achieve a better performance by accessing gradient data instead of using .at(i,j) for each pixel.
Hope it helps!
I am using OpenCV4Android to process my images. I wanted to preform Illumination Normalization which was linked to me with this work:
http://lear.inrialpes.fr/pubs/2007/TT07/Tan-amfg07a.pdf
furthermore I was given COMPLETE IMPLEMENTATION in C++ (OpenCV):
https://github.com/bytefish/opencv/blob/master/misc/tan_triggs.cpp
I tried to rewrite this code do Java, but I think there might be mistake somewhere. So, what I get from this alghorithm is close but not good enough. Check the expected results on the PDF above on page for example 12. And this is what i get:
https://dl.dropboxusercontent.com/u/108321090/a1.png
https://dl.dropboxusercontent.com/u/108321090/Screenshot_2013-12-31-14-09-25.png
So there is still too much noise between background and face features, but I think it's my fault here. This is my code:
//GET IMAGE URI
Uri selectedImage = imageReturnedIntent.getData();
//CREATE BITMAP FROM IT
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bmp = BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage),
null, bmpFactoryOptions);
//CREATE OPENCV MAT OBJECT
Mat imageMat = new Mat();
Utils.bitmapToMat(bmp, imageMat);
//CONVERT TO GRAYSCALE
Mat grayMat = new Mat();
Imgproc.cvtColor(imageMat, grayMat, Imgproc.COLOR_BGR2GRAY);
//CUT OUT FACE FROM WHOLE IMAGE
(...) face detection cascades localize face and writes the region where face is located
in array, then I create mat with only face in it:
Mat cleanFaceMatGRAY = new Mat();
cleanFaceMatGRAY = new Mat(faceDetectMatGRAY, facesArray[0]);
//PROCESSING OF MAT WITH FACE (alghorithm from PDF & .cpp file)
Mat I = tan_triggs_preprocessing(cleanFaceMatGRAY);
Core.normalize(I, I,0, 255, Core.NORM_MINMAX, CvType.CV_8UC1);
//DISPLAY MAT IN IMAGEVIEW
ivPickedPhoto.setImageBitmap(AppTools.createBitmapFromMat(I, Bitmap.Config.ARGB_8888));
And method with algorithm (as u can see its total copy-paste from .cpp file with edited/rewrited methods to OpenCV4Android):
private Mat tan_triggs_preprocessing(Mat image) {
float alpha = 0.1f;
float tau = 10.0f;
float gamma = 0.2f;
int sigma0 = 1;
int sigma1 = 2;
// Convert to floating point:
Mat X = image;
X.convertTo(X, CvType.CV_32FC1);
// Start preprocessing:
Mat I = new Mat();
Core.pow(X, gamma, I);
// Calculate the DOG Image:
{
Mat gaussian0 = new Mat();
Mat gaussian1 = new Mat();
// Kernel Size:
int kernel_sz0 = (3*sigma0);
int kernel_sz1 = (3*sigma1);
// Make them odd for OpenCV:
kernel_sz0 += ((kernel_sz0 % 2) == 0) ? 1 : 0;
kernel_sz1 += ((kernel_sz1 % 2) == 0) ? 1 : 0;
Size ksize1 = new Size(kernel_sz0,kernel_sz0);
Size ksize2 = new Size(kernel_sz1,kernel_sz1);
Imgproc.GaussianBlur(I, gaussian0, ksize1, sigma0, sigma0, Imgproc.BORDER_CONSTANT);
Imgproc.GaussianBlur(I, gaussian1, ksize2, sigma1, sigma1, Imgproc.BORDER_CONSTANT);
Core.subtract(gaussian0, gaussian1, I);
}
{
double meanI = 0.0;
{
Mat tmp = new Mat();
Mat abstmp = new Mat();
Core.absdiff(I, new Scalar(0), abstmp);
Core.pow(abstmp, alpha, tmp);
meanI = Core.mean(tmp).val[0];
}
Core.divide( Math.pow(meanI, 1.0/alpha), I, I);
}
{
double meanI = 0.0;
{
Mat tmp = new Mat();
Mat abstmp = new Mat();
Mat mintmp = new Mat();
Core.absdiff(I, new Scalar(0), abstmp);
Core.min(abstmp, new Scalar(tau), mintmp);
Core.pow(mintmp, alpha, tmp);
meanI = Core.mean(tmp).val[0];
}
Core.divide( Math.pow(meanI, 1.0/alpha), I, I);
}
// Squash into the tanh:
{
for(int r = 0; r < I.rows(); r++) {
for(int c = 0; c < I.cols(); c++) {
I.get(r,c)[0] = Math.tanh(I.get(r,c)[0]) / tau;
}
}
Core.multiply(I,new Scalar(tau), I);
}
return I;
}
And what I didn't understand while I was rewriting this code was the iteration over the matrix. In .cpp there was
I.at<float>(r,c)
Where I have replaced it with just:
I.get(r,c)[0]
Do you think I might have lost some data here so thats why image is shady?