0

I am writing an OpenCV based image processing algorythm for thresholding. The algorythm is written here in C++ language and I am rewriting in on Java, for Android studio. In one line, I have to add two Mat (OpenCV matrix) objects. In C++ it is res=Img+res;, in Java Core.add(imgMat, res, res);. At this line i get an error, which I cannot solve:

CvException: /Volumes/./././././././arithm.cpp:639: error: (-209) The operation is neither 'array op array' (where arrays have the same size and the same number of channels), nor 'array op scalar', nor 'scalar op array' in function void cv::arithm_op(...)

In the code below you could see, that both Mat objects have the same size and it has the same format (CvType) too. Again, how the code looks in C++, you can see in this question.

My code (java):

public Bitmap Thresholding(Bitmap bitmap)
{
    Mat imgMat = new Mat();
    Utils.bitmapToMat(bitmap, imgMat);
    imgMat.convertTo(imgMat, CvType.CV_32FC1, 1.0 / 255.0);

    Mat res = CalcBlockMeanVariance(imgMat, 21);
    Core.subtract(new MatOfDouble(1.0), res, res);
    Core.add(imgMat, res, res);

    Imgproc.threshold(res, res, 0.85, 1, Imgproc.THRESH_BINARY);
    //Imgproc.resize(res, res, new org.opencv.core.Size(res.cols() / 2, res.rows() / 2));

    res.convertTo(res, CvType.CV_8UC1, 255.0);
    Utils.matToBitmap(res, bitmap);

    return bitmap;
}

public Mat CalcBlockMeanVariance (Mat Img, int blockSide)
{
    Mat I = new Mat();
    Mat ResMat;
    Mat inpaintmask = new Mat();
    Mat patch;
    Mat smallImg = new Mat();
    MatOfDouble mean = new MatOfDouble();
    MatOfDouble stddev = new MatOfDouble();

    Img.convertTo(I, CvType.CV_32FC1);
    ResMat = Mat.zeros(Img.rows() / blockSide, Img.cols() / blockSide, CvType.CV_32FC1);

    for (int i = 0; i < Img.rows() - blockSide; i += blockSide)
    {
        for (int j = 0; j < Img.cols() - blockSide; j += blockSide)
        {
            patch = new Mat(I,new Rect(j,i, blockSide, blockSide));
            Core.meanStdDev(patch, mean, stddev);

            if (stddev.get(0,0)[0] > 0.01)
                ResMat.put(i / blockSide, j / blockSide, mean.get(0,0)[0]);
            else
                ResMat.put(i / blockSide, j / blockSide, 0);
        }
    }

    Imgproc.resize(I, smallImg, ResMat.size());
    Imgproc.threshold(ResMat, inpaintmask, 0.02, 1.0, Imgproc.THRESH_BINARY);

    Mat inpainted = new Mat();
    Imgproc.cvtColor(smallImg, smallImg, Imgproc.COLOR_RGBA2BGR);
    smallImg.convertTo(smallImg, CvType.CV_8UC1, 255.0);

    inpaintmask.convertTo(inpaintmask, CvType.CV_8UC1);
    Photo.inpaint(smallImg, inpaintmask, inpainted, 5, Photo.INPAINT_TELEA);

    Imgproc.resize(inpainted, ResMat, Img.size());
    ResMat.convertTo(ResMat, CvType.CV_32FC1, 1.0 / 255.0);

    return ResMat;
}

Thank you in advance.

Community
  • 1
  • 1
Dainius Šaltenis
  • 1,644
  • 16
  • 29
  • Please add some prints showing `imgMat` and `res` sizes and channels before calling `add` – Miki Jan 16 '16 at 16:11
  • Sizes: 1280x960 imgMat and 1280x960 res (same) ; Channels: 4 imgMat and 3 res (not the same), so I suspect the problem is here, right? But before add I do `imgMat.convertTo(imgMat, CvType.CV_32FC1, 1.0 / 255.0);` and `ResMat.convertTo(ResMat, CvType.CV_32FC1, 1.0 / 255.0);`. How should I convert to maintain same amount of channels? I had some errors with `Utils.matToBitmat()` function, it said image has to be CV_8UC1 or CV_8UC3, and changing CV solved it, but how to solve this then? – Dainius Šaltenis Jan 16 '16 at 16:25
  • 1
    add `Imgproc.cvtColor( imgMat, imgMat, Imgproc.COLOR_BGRA2BGR);` before calling `add`, so imgMat number of channels is 3 – Miki Jan 16 '16 at 16:28
  • It worked. Post it as an answer, please, if you can, I will accept it then (won't have to wait 2 days for accepting my own). Thank you a lot for helping me the second time :). – Dainius Šaltenis Jan 16 '16 at 16:35
  • This method of thresholding, by the way, seems to be very sensitive to shadows. My method of adaptive thresholding cleared them away, but this one processes the text better in a well photographed places of paper. I suppose you are good at this kind of stuff (OpenCV), could you maybe give an advice for me to try, how to avoid that? (it is now first time I managed to set this method up; I am using it for OCR) – Dainius Šaltenis Jan 16 '16 at 16:38
  • That could be an interesting topic for another question. I (we) need more details and some example images with your results and expected results in order to understand better. – Miki Jan 16 '16 at 16:41
  • 1
    Ok. I'll try to solve this myself, to search for some information, but if I will not manage to improve this, I will post a very detailed question. I am very new to OpenCV, so it is hard to do something good with this tool. Thanks again. – Dainius Šaltenis Jan 16 '16 at 16:48

1 Answers1

1

While imgMat and res have the same size, they have different number of channels: imgMat has 4 channels and res has 3 channels.

Since you can add two matrices only if they have same size and number of channels, you can convert imgMat to a 3 channel image before calling add like:

Imgproc.cvtColor( imgMat, imgMat, Imgproc.COLOR_BGRA2BGR);
Miki
  • 40,887
  • 13
  • 123
  • 202