Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to improve color layer mask to have mid tones?

I would like to improve the layer mask that I am creating in Python. Although my mask pretty much hits the targeted color, my main problem with it, is it is doing so in binary, the pixel is either pure white or pure black. I'm unable to extrapolate the intensity of the color. I want to achieve something like how Photoshop does it wherein there are mid-tones of grey on the mask.

enter image description here enter image description here

Here is the current attempt: import cv2

image = cv2.imread('grade_0.jpg')

lower = np.array([0,0,0])
upper = np.array([12,255,255])

mask = cv2.inRange(cv2.cvtColor(image, cv2.COLOR_BGR2HSV), lower, upper)  
mask = 255 - mask
# mask = cv2.bitwise_not(mask) #inverting black and white
output = cv2.bitwise_and(image, image, mask = mask)

cv2.imshow("output", output)
cv2.imshow("mask", mask)
cv2.waitKey()

enter image description here enter image description here

Here are the plain images.

enter image description here enter image description here

like image 392
DrakeJest Avatar asked Oct 23 '25 14:10

DrakeJest


1 Answers

Biiiiiig picture first. It's clickable and should be clicked. Let your eyes wander.

enter image description here

Pick your parameters:

  • The stain color you're interested in. I assumed some type of dark red/brown.
  • The distance function. I picked a gaussian. It's nice.
  • The parameters of the distance function. I show a bunch of sigmas, and two particular ways to weigh the colors.

Common definitions and functions:

import numpy as np
import cv2 as cv

target = (75, 105, 150) # BGR

subject = cv.imread(...)

distvecs = subject - np.float32(target)[None, None, :]

One flavor of weighting the color differences:

distvecs *= (0.114, 0.587, 0.299) # blue weighted least, according to perception
distance = distvecs.sum(axis=2) # manhattan distance

Other flavor of weighting the color differences:

# equal weight, euclidean distance
distance = np.linalg.norm(distvecs, axis=2)

You can come up with whatever you like. You could even mess around with color spaces. There are no rules.

Applying the gaussian to the distances:

def gaussian(x, sigma):
    return np.exp(-np.power(x, 2) / (2 * np.power(sigma, 2)))

def max_normalize(x):
    return x / x.max()

scored = max_normalize(gaussian(distance, sigma))

And that's the "mask".

And here's another result with a different target color, BGR tuple (68, 60, 100)

enter image description here

And another, for (121, 45, 87):

enter image description here


I'm surprised that everyone seems to do some kind of threshold, i.e. visible discontinuities.

There is some of that in my solution too, but only where the pictures contain high frequency components (strong gradients).

like image 132
Christoph Rackwitz Avatar answered Oct 26 '25 05:10

Christoph Rackwitz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!