OpenCV: Removing red pixels that are not structurally supported by a fabric/thread mask (mask misfit issue)

1 week ago 11
ARTICLE AD BOX

Problem Description

From the same input image, I compute two binary masks:

red_mask – all red-colored pixels (0 or 255)

fabric_mask – detected fabric/thread structure (0 or 255)

Both masks are correct individually and pixel-aligned.

My goal is to keep only red pixels that are structurally supported by the fabric threads, and remove red pixels that lie across gaps or outside the thread structure.


What I Expected to Happen

When combining the two masks, I expected the result to:

Preserve red pixels that lie along fabric threads

Remove red pixels that:

Fill thread gaps

Cross threads without following their geometry

Are not supported by nearby fabric pixels

In other words, the red pixels should remain only where the fabric structure exists continuously underneath them.


What Actually Happens

Using a direct logical operation:

result = cv2.bitwise_and(red_mask, fabric_mask)

produces the following undesired but technically correct result:

Red pixels disappear in thin or broken fabric regions

Red pixels survive in areas where they only touch the structure at a few pixels

Red regions partially overlapping the fabric remain even if they span gaps

This happens because bitwise_and only checks per-pixel overlap, not geometric or structural consistency.

So while the operation is mathematically correct, it is semantically incorrect for this problem.


Minimal Reproducible Example

import cv2 import numpy as np img = cv2.imread("input.png") # Red mask hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) lower_red1 = np.array([0, 70, 30]) upper_red1 = np.array([10, 255, 255]) lower_red2 = np.array([170, 70, 30]) upper_red2 = np.array([180, 255, 255]) red_mask = ( cv2.inRange(hsv, lower_red1, upper_red1) | cv2.inRange(hsv, lower_red2, upper_red2) ) # Fabric structure mask (precomputed) fabric_mask = cv2.imread("fabric_mask.png", cv2.IMREAD_GRAYSCALE) # Logical combination result = cv2.bitwise_and(red_mask, fabric_mask) cv2.imwrite("result.png", result)

Why This Is Not Sufficient

Although the operation is mathematically valid, it does not encode the actual requirement:

Structural continuity

Neighborhood support

Alignment with thin, directional features

This problem is not a simple Boolean masking problem, but a structural consistency problem.


What I Am Looking For

A classical OpenCV / mathematical approach to remove red pixels that are:

Not continuously supported by the fabric structure

Only touching the structure at isolated pixels

Crossing fabric gaps or voids

Examples of acceptable approaches:

Distance-transform–based support filtering

Neighborhood-based validation

Skeleton or thickness consistency checks

Directional morphology aligned to fabric orientation


Important Note

A purely classical solution is preferred.
If this is provably not solvable using mathematical morphology alone, a lightweight model-based approach may be considered only as a last option.


enter image description here

Question

What is a correct classical CV approach to enforce structural support between two aligned binary masks, beyond simple pixel-wise logical operations?

Read Entire Article