2

I have a 4-channel image (.png, .tif) like this one:

enter image description here

I am using OpenCV, and I would like to add padding of type BORDER_REFLECT around the flower. copyMakeBorder is not useful, since it adds padding to the edges of the image.

I can add certain padding if I split the image in bgr + alpha and apply dilate with BORDER_REFLECT option on the bgr image, but that solution spoils all the pixels of the flower.

Is there any way to perform a selective BORDER_REFLECT padding addition on a ROI defined by a binary mask?

EDIT:

The result I expect is something like (sorry I painted it very quickly with GIMP) :

enter image description here

I painted two black lines to delimit the old & new contour of the flower after the padding, but of course those lines should not appear in the final result. The padding region (inside the two black lines) must be composed by mirrored pixels from the flower (I painted it yellow to make it understandable).

Finfa811
  • 618
  • 1
  • 8
  • 28
  • Can you please show the expected result? – Miki Mar 16 '16 at 18:46
  • I cannot show a proper expected result because that is the idea, obtaining it programatically, but I edited the question to show an approximate result that I painted using GIMP. Sorry for the inaccuracy but I did it very quickly, but hope you can understand the desired result. – Finfa811 Mar 16 '16 at 19:12
  • Nice, much clearer now. No, it's not something you can do with `copymakeborder`. Not even with `dilate` or similar, probably. Interesting, though. – Miki Mar 16 '16 at 19:13
  • A quick hack could probably be to draw the original flower over a little larger flower. you can do that with `resize` – Miki Mar 16 '16 at 19:16
  • That I've tried, but with that solution the padding is kind of a `BORDER_WRAP` style (cdefgh|abcdefgh). And I am interested in a `BORDER_REFLECT` fashion, i.e., mirroring the pixels (fedcba|abcdefgh). I know the issue is not simple, but I'm running out of ideas :( – Finfa811 Mar 16 '16 at 19:24
  • 1
    @Finfa811 if you only want to add so little the best way would be to just scale the image by a few percent. any other solution would give you head aches because you would have to get rid of the boarder between flower and newly added stuff – Piglet Mar 16 '16 at 19:31
  • Yep, that sounds reasonable @Piglet . Finfa, why do you want to do this? Can you explain your "main" application? – Miki Mar 16 '16 at 19:33
  • and I'd like to add that any other solution than scaling the entire flower will look stupid and unnatural. no matter how good your algorithm is. the more you add the sooner you'll realize that something was added. You could also extract the petals, scale them, rotate them a bit and put them behind the original flower so it will look like a second layer of petals. I guess that would be the best solution – Piglet Mar 16 '16 at 19:36
  • @Piglet the idea is having a general solution to pad a specific number of pixles. Actually the border between flower and new stuff can be easily detected using the alpha channel of the image, because we have available the binary mask that segments between foreground and background. – Finfa811 Mar 16 '16 at 19:40
  • You can probably use [inpainting](http://docs.opencv.org/trunk/df/d3d/tutorial_py_inpainting.html#gsc.tab=0) for this without reinventing the wheel – Miki Mar 16 '16 at 19:43
  • @Finfa811 of course you can detect the boarder easily, but can you remove it so you see no transition between old and new? You'll have to add and remove shadows and higlights in a pretty complicated manner to make it look good. You can scale the petals to get a defined amount of new pixels. – Piglet Mar 16 '16 at 19:47
  • @Miki the "main" is texture blending. If I want to use pyramidal (or multi-band) blending, bluring and resizing the flower will introduce artifacts in the final result, so I need to add certain padding to the foreground, and a mirrored border provides the best results – Finfa811 Mar 16 '16 at 19:48
  • Thank you both, I'll give it a try with inpaint. – Finfa811 Mar 16 '16 at 20:09
  • @Finfa811 and botching some "mirrored" pixels all around won't cause any artifacts? I don't believe that. Most of it will be poorly interpolated anyway because the circumference grows bigger with every pixel you add – Piglet Mar 16 '16 at 20:09
  • If you add padding and keep original mask, it will avoid black pixels from background to blur with foreground. Actually that is the method that OpenCV stitching pipeline uses after warping the images. I want to apply it to texture blending. – Finfa811 Mar 16 '16 at 20:14

2 Answers2

3

A simple python script to resize the image and copy the original over the enlarged one will do the trick.

import cv2

img = cv2.imread('border_reflect.png', cv2.IMREAD_UNCHANGED)

pad = 20
sh = img.shape
sh_pad = (sh[0]+pad, sh[1]+pad)
imgpad = cv2.resize(img, sh_pad)

imgpad[20:20+sh[0], 20:20+sh[1], :][img[:,:,3]==255] = img[img[:,:,3]==255]
cv2.imwrite("padded_image.png", imgpad)

Here is the result

enter image description here

But that doesn't look very 'centered'. So I modified the code to detect and account for the offsets while copying.

import cv2

img = cv2.imread('border_reflect.png', cv2.IMREAD_UNCHANGED)

pad = 20
sh = img.shape
sh_pad = (sh[0]+pad, sh[1]+pad)
imgpad = cv2.resize(img, sh_pad)

def get_roi(img):
    cimg = img[:,:,3].copy()

    contours,hierarchy = cv2.findContours(cimg,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

    #Remove the tiny pixel noises that get detected as contours
    contours = [cnt for cnt in contours if cv2.contourArea(cnt) > 10]

    x,y,w,h = cv2.boundingRect(cnt)
    roi=img[y:y+h,x:x+w]
    return roi

roi = get_roi(img)
roi2 = get_roi(imgpad)

sh = roi.shape
sh2 = roi2.shape

o = ((sh2[0]-sh[0])/2, (sh2[1]-sh[1])/2)

roi2[o[0]:o[0]+sh[0], o[1]:o[1]+sh[1], :][roi[:,:,3]==255] = roi[roi[:,:,3]==255]
cv2.imwrite("padded_image.png", imgpad)

Looks much better now

enter image description here

Vasanth
  • 1,238
  • 10
  • 14
  • Thank you for your answer. I tried that as a first approach, but actually the real solution is more complicated, since padded pixels should be mirrored from the flower. – Finfa811 Mar 16 '16 at 20:01
  • Just saw your edit. Like Piglet pointed out, mirroring the flower's pixels would make the shadows around the petals look unnatural also take into account the ever increasing blur due to lack of enough pixels in the inner regions. His solution of adding a rotation before stacking would probably give a better looking result for this example. Implementing mirroring would involve a bit of region growth. Will try that if I get time just for the fun of it :). – Vasanth Mar 16 '16 at 20:50
0

The issue has been already addressed and solved here:

http://answers.opencv.org/question/90229/add-padding-to-object-in-4-channel-image/

Finfa811
  • 618
  • 1
  • 8
  • 28