Resizing Graphic Designs With Transparency

Hello,

currently, I have to resize a lot of graphic designs by hand in photoshop. I would like to automate this task using OpenCV but I’m struggling a bit with design quality.

Original Image
Resized Image

The problem is that the resized image has white pixels on the edges of the transparency. I guess this is because of the interpolation. (I tried all types already)

Does anyone have an idea how I could resize Images without that problem?
Otherwise, I will have to look into Photoshop Scripting… I would prefer to keep everything in Python though.

I’m using the following code:

    image = cv2.imread("original.png", cv2.IMREAD_UNCHANGED)
    height = image.shape[0]  # 5400
    width = image.shape[1]  # 4500
    new_height = int(height * 0.9)
    new_width = int(width * 0.9)

    resized_image = cv2.resize(image, (new_width, new_height), interpolation=cv2.INTER_AREA)
    cv2.imwrite("resized.png", resized_image)

Here is the link to the Image I’m using:
https://i.ibb.co/BfD4pzF/original.png

welcome.

I believe ImageMagick is a more suitable tool for batch-processing of picture files.

I’ll check out your original file.

OpenCV is not made to deal with alpha channels. it can read and write the format. it has no functions to operate on such pictures. there is no easy fix, no single function to do what you need. this issue needs some thought.

the issue with alpha channels is that most people don’t know how they really work, how to work with them.

let’s take the black lines adjacent to transparent areas. pixels in the fully transparent region don’t matter, so they can have arbitrary RGB values, but pixels on the edge do matter. those have to have the same color value as fully opaque pixels, and the alpha channel modulates that.

if such a picture is resized trivially, adjacent fully transparent pixels, which have arbitrary RGB values, get mixed into the edge pixels’ color, and that destroys things. the resize completely ignores the alpha channel in its operation, treats all channels separately.

what you need to do is fill those transparent (alpha 0) pixels’ values from neighboring non-0 pixels.

there are likely a lot of ways to solve this, some may even be easy and cheap.

without giving it much thought, I’d advise to use inpainting. use (alpha == 0) for the mask of pixels that need inpainting. you only need bordering pixels and they only need to replicate nearby non-transparent color. inpainting usually does way more than that.

perhaps use a mask like (alpha == 0) & dilate(alpha > 0), which only selects those adjacent pixels.

https://docs.opencv.org/master/df/d3d/tutorial_py_inpainting.html

1 Like

something like this… parameters somewhat guessed and the result might not always be right. I can’t quite predict the complex operation of cv.inpaint. I hope it’s just respecting non-masked data within the given radius.

im = cv.imread("original.png", cv.IMREAD_UNCHANGED)
alpha = im[...,3]
adjacent = ((alpha == 0) & cv.dilate((alpha > 0).astype(np.uint8), None, iterations=3))
fixed = cv.inpaint(im[..., 0:3], adjacent, 1, flags=cv.INPAINT_NS) # or _TELEA, not sure
im[...,0:3] = fixed
1 Like

Hello crackwitz,

thanks a lot for you help. I didnt know anything about ImageMagick but i’ll take a look at it for sure!

The problem is, resizing is only one of the steps I have to do. That’s why I would like to implement everything in python to do my full workflow with only one click.

I will take a look into it and see if i can get it working.
I have to see if i find out how masks work. I struggled with them in the past.

Thanks so much for your help.

in addition to the snippet I gave I can say that proper image editors seem to do it right. Paint.NET doesn’t give this resampling artefact. it’s very likely that ImageMagick would do the right thing as well… there should be an API for it, if you still decide to use it.

1 Like

Ohh it has an API, that’s awesome! I thought it’s just a tool to use. I’ll see if I can get the snippet working.

Thanks so much for your help.

I have to add a disclaimer to that code I gave above…

proper alpha-aware resizing should weigh a pixel’s source contributions by their alpha values (as well as any bilinear or other interpolation). since OpenCV’s resize doesn’t do that, it will incorporate fully transparent pixels if they’re within the interpolation area. filling those with a plausible color from non-transparent pixels is a hack and mathematically incorrect… but I struggle to come up with a plausible situation where it would be visible, let alone noticeable.