Ask Your Question
1

copyMakeBorder returns un-solid border

asked 2018-03-05 09:43:27 -0600

updated 2018-03-07 10:39:07 -0600

Goal: Adding a solid white line to a black'n'white image.

I'm trying to extract text from an image by cropping it and then adding a solid border with copyMakeBorder(). My problem is that I can't make the border solid. It seems like the copyMakeBorder() uses information from my initial image instead.

This is my code:

void OcvCardReader::cropToAreaWithSolidBorder(Mat image, const Rect2f area) {
    //Crop the image.
    image = image(area);
    //Add the border.
    int borderSize = 10;
    copyMakeBorder(image, image,
        borderSize, borderSize, borderSize, borderSize,
        BORDER_CONSTANT, Scalar(255));
}

My input image looks like this: Input image

This is after the crop: Cropped image

And finally, after adding the border: image description

Note the black pixels att the bottom left. I had expected a border to be white all around. I also tried to use Scalar(0) to see if it makes any difference. It doesn't.

Curiously, it works well if I convert the image to a 3-channel Mat and then use Scalar(255, 255, 255), but that seems like a detour to me.

So, why does copyMakeBorder() return a border that isn't solid?

edit retag flag offensive close merge delete

Comments

it's only part of the problem, but please use cropToAreaWithSolidBorder(Mat &image, ...) (pass a reference) else your Mat header is not updated after calling the function

berak gravatar imageberak ( 2018-03-05 11:43:20 -0600 )edit

Oh! I thought a Mat was big enough to be passed by reference automagically. Thanks! I will try that! :-D

Björn Larsson gravatar imageBjörn Larsson ( 2018-03-06 03:08:20 -0600 )edit

it's not about the size, but about manipulating a copy (the pixels will be changed, but not the Mat header (rows,cols and such)

berak gravatar imageberak ( 2018-03-06 03:24:41 -0600 )edit
1

From the doc:

When the source image is a part (ROI) of a bigger image, the function will try to use the pixels outside of the ROI to form a border. To disable this feature and always do extrapolation, as if src was not a ROI, use borderType | BORDER_ISOLATED.

Is it what you got?

Eduardo gravatar imageEduardo ( 2018-03-06 07:26:02 -0600 )edit
1

Also, be careful with in-place parameters (src and dst objects are the same). Some OpenCV functions do not operate with in-place parameters.

Eduardo gravatar imageEduardo ( 2018-03-06 07:27:34 -0600 )edit

1 answer

Sort by » oldest newest most voted
1

answered 2018-03-07 09:49:36 -0600

updated 2018-03-07 09:51:13 -0600

So, I've tried a few different solutions based on the comments I got.

First I tried to change the call to call by reference, as @berak suggested. It might have changed something in the overhead but it did no visible change to the image.

void OcvCardReader::cropToAreaWithSolidBorder(Mat& image, const Rect2f area) {
    //Crop the image.
    image = image(area);
    //Add the border.
    int borderSize = 10;
    copyMakeBorder(image, image,
        borderSize, borderSize, borderSize, borderSize,
        BORDER_CONSTANT, Scalar(255));
}

Then I changed to use BORDER_ISOLATED instead of BORDER_CONSTANT, as @Eduardo suggested. It worked like a charm!

void OcvCardReader::cropToAreaWithSolidBorder(Mat& image, const Rect2f area) {
    //Crop the image.
    image = image(area);
    //Add the border.
    int borderSize = 10;
    copyMakeBorder(image, image,
        borderSize, borderSize, borderSize, borderSize,
        BORDER_ISOLATED, Scalar(255));
}

I also managed to find a book article suggesting the use of another crop-method, and that worked as well.

void OcvCardReader::cropToAreaWithSolidBorder(Mat& image, const Rect2f area) {
    //Crop the image.
    float centerX = area.x + area.size().width / 2;
    float centerY = area.y + area.size().height / 2;
    Point2f center(centerX, centerY);
    getRectSubPix(image, area.size(), center, image);
    //Add the border.
    int borderSize = 10;
    copyMakeBorder(image, image,
        borderSize, borderSize, borderSize, borderSize,
        BORDER_CONSTANT, Scalar(255));
}

Which solution one goes for is a matter of choice, I guess. I will be reading up a bit more based on the given comments to gain a better understanding of how the methods works. My code will probably be a combination of the mentioned solutions in the end.

edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2018-03-05 09:43:27 -0600

Seen: 857 times

Last updated: Mar 07 '18