Ask Your Question

Replace Color of Components that have specific color and are have transparent pixels as neighbours

asked 2020-08-23 08:57:52 -0600

Equintox gravatar image

updated 2020-08-27 11:46:07 -0600

Hello, I recently started with opencv and i need a color-replacement logic for image processing. My Images are RGB with transparent background. (I think this is the main reason i struggle)

What i want to do:

  • Search for groups that only exist of 0xFFF (White)
  • Replace them with 0x000 (Black), but only if the shape has a transparent pixel as a neighbour.

image description

image description

I tried working with connectedComponentsWithStats but the problem is it does not work with rgb + transparent images.

Does anyone have an idea and a hint for me how I could start?

Which methods/algorithms do you recommend for me?

I'm thankful for any kind of help!

Cheers Stefan

edit retag flag offensive close merge delete


is this a homework?

sturkmen gravatar imagesturkmen ( 2020-08-23 09:15:19 -0600 )edit

No, It's for my business. I have t-shirts designs that contain animal illustration and a text. I want to invert the color of the text (which is white), but keep animal eyes in white.

Want to automate this process with opencv. Currently i'm doing it by hand in photoshop.

But you are right, it sounds like a homework hehe. I'm just asking for inspiration how I can solve my problem and which algorithms could work out of the box for this problem.

Equintox gravatar imageEquintox ( 2020-08-23 14:04:50 -0600 )edit

do you provide a real image and a result you get from photoshop

sturkmen gravatar imagesturkmen ( 2020-08-23 14:40:11 -0600 )edit

Yes, I added a sample of what i'm trying to do in detail.

Equintox gravatar imageEquintox ( 2020-08-23 15:47:40 -0600 )edit

i will try to suggest a solution when i find a free time

sturkmen gravatar imagesturkmen ( 2020-08-25 12:47:14 -0600 )edit

@Equintox could you provide a sample image that have real alpha channel

sturkmen gravatar imagesturkmen ( 2020-08-30 02:53:26 -0600 )edit
Equintox gravatar imageEquintox ( 2020-08-30 10:50:58 -0600 )edit

1 answer

Sort by ยป oldest newest most voted

answered 2020-08-30 12:44:25 -0600

updated 2020-09-10 01:13:30 -0600

EDIT1 : you can find a test python code here

you could try the code below, it works for the image you provided. you can ping me if you have other pictures that fails :)


roi = roi - Scalar(255, 255, 0);

in this line i used Scalar(255, 255, 0) produces a red color instead of white.

for black use Scalar(255, 255, 255) or calculate proper Scalar for other colors.

#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main(int argc, char** argv)
    Mat src = imread("e:/test/3903-lloyd-cw30-dont-worry-be-hoppy-W.png",-1);
    if (src.empty())
        return -1;

    Mat bw, bgra[4];
    split(src, bgra);

    vector<vector<Point> > contours;
    findContours(bgra[3], contours, RETR_TREE, CHAIN_APPROX_SIMPLE);

    Rect textRect;

    for (size_t i = 0; i < contours.size(); i++)
        Rect r = boundingRect(contours[i]);
        Mat roi = src(r);
        Mat mask = bgra[3](r);

        Scalar smean = mean(roi,mask);

        if( (smean[0] > 240) & (smean[1] > 240) & (smean[2] > 240))
            if (textRect == Rect())
                textRect = r;
                textRect = textRect | r;

    Mat roi = src(textRect);
    roi = roi - Scalar(255, 255, 0); // don't touch alpha channel otherwise you lose smooth alpha effects
    imwrite("e:/test/src.png", src);
    return 0;
edit flag offensive delete link more


I will try it out tomorrow. Thanks so much.

Equintox gravatar imageEquintox ( 2020-08-31 12:39:15 -0600 )edit

Thanks a lot for your help sturkmen, it definitely helped me in the right direction, but i wasn't able to finish the algorithm. I tried to rewrite the code to python (as all my other code is in python) but i couldn't finish it. It is also possible that the text is across multiple rectangles.

def invert_font_color(path):
    image = cv2.imread(path, cv2.IMREAD_UNCHANGED)
    b, g, r, a = cv2.split(image)

    contours, hierarchy = cv2.findContours(a, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
    cv2.drawContours(image, contours, -1, (0, 255, 0), 1)

    cv2.imshow('image', image)

With this code i find the contours exactly as i need them.

Equintox gravatar imageEquintox ( 2020-09-08 03:58:14 -0600 )edit

What i need to do now is:

  • Bloodfill any of the contours into a shape
  • Create masks with each shape (bloodfilled contour)
  • Iterate over the original image and check if the original image (R,G,B) with an applied mask of a single shape (e.g. a letter) contains average pixels of >= (240,240,240)
  • If so, -> replace color of the roi (shape position ) to #1c1c1c

Equintox gravatar imageEquintox ( 2020-09-08 04:02:36 -0600 )edit

Please post your Python code as an answer let me try to improve it

sturkmen gravatar imagesturkmen ( 2020-09-08 14:30:57 -0600 )edit

Hey, i tried really a lot of different opencv algorithms but i didnt get it working with the masking/ calculating mean of areas etc...

i tried to do a brute-force solution and ended up with this:

For some testing images it worked, but i really need to improve it. It would already help me if you could suggest cv algorithms that i could try to use.

Thanks so much for your help!

Equintox gravatar imageEquintox ( 2020-09-09 14:35:05 -0600 )edit
sturkmen gravatar imagesturkmen ( 2020-09-10 01:14:52 -0600 )edit

Exactly what i needed. Thanks so much man..

Equintox gravatar imageEquintox ( 2020-09-10 11:49:31 -0600 )edit

i am not a pyhton coder and i wonder if there is an alternative of ( one line instead of 3)

        image[yOffset:,xOffset:][:height,:width][:, :, 0] = 0
        image[yOffset:,xOffset:][:height,:width][:, :, 1] = 0
        image[yOffset:,xOffset:][:height,:width][:, :, 2] = 0
sturkmen gravatar imagesturkmen ( 2020-09-10 11:55:11 -0600 )edit

Really man, thanks so much. Maybe changing it to: but i don't know if this is better.

image[yOffset:, xOffset:][:height, :width][:, :] &= np.array([0, 0, 0, 255], dtype=np.uint8)

The algorithm works now for 95% of the images and will save me around 2 hours of boring work per week.

Equintox gravatar imageEquintox ( 2020-09-11 01:33:22 -0600 )edit

There are 3 issues left but i don't know if and how they could be fixed easily:

  • Letter is connected to main graphic --> With this approach this can't be fixed, but this case is rare

  • Also, colored pixels of the main graphic get replaced (see image above) --> ROI/Mask should be the shape, not the boundaries but I don't know if this can be done easily

  • If the text is curved and a two shapes share the same pixels: --> Maybe save each inverted shape in an array and merge them in the end

In case you want to try here are the images, otherwise, it's fine. I'm already happy with the solution.

Equintox gravatar imageEquintox ( 2020-09-11 01:43:21 -0600 )edit

Question Tools

1 follower


Asked: 2020-08-23 08:57:52 -0600

Seen: 1,732 times

Last updated: Sep 10 '20