I'm looking for a algorithm similar adaptive thresholding, but that keeps color. I'm trying take an image like this:
And make it look like this:
If it matters, I'm working in ios.
Here's a CIKernel that works well on your sample image
kernel vec4 coreImageKernel (sampler i)
{
vec2 dc = destCoord();
// center pixel color
vec4 c = unpremultiply(sample(i, samplerTransform(i,dc+vec2(0.0,0.0))));
// for a whiteboard, the max of a neighborhood is likely to be the color
// of the whiteboard
vec4 cmax = c;
cmax = max(unpremultiply(sample(i, samplerTransform(i,dc+vec2(10.0,0.0)))), cmax);
cmax = max(unpremultiply(sample(i, samplerTransform(i,dc+vec2(-10.0,0.0)))), cmax);
cmax = max(unpremultiply(sample(i, samplerTransform(i,dc+vec2(0.0,10.0)))), cmax);
cmax = max(unpremultiply(sample(i, samplerTransform(i,dc+vec2(0.0,-10.0)))), cmax);
// normalize the center color according to the whiteboard color
vec4 r = c / cmax;
return premultiply(r);
}
So how does this work? Well the first part of the kernel, the part that calculates cmax, is calculating the local color of the whiteboard. This is the tricky part. Basically it determines (approximately) the color that whiteboard would be if there where no markings on it. To do this the kernel makes three key assumptions:
Here's what the output of cmax looks like:
Once the local whiteboard color is approximated it is just a matter of dividing the current pixel by the local background. This is similar to how a color cast is removed from an image.
This algorithm is similar to the Haze Removal example from the WWDC13 Core Image presentation. In that example a local min is subtracted to make blacker blacks. In this case a local max is divided to make whiter whites.
:
Thresholding always results in a binary mask, i.e. pixels that are below the (local adaptive) threshold and pixels that are above. If you have that mask you can of course keep the color information of the original image.
Therefore a simple approach would result in the following workflow:
Alternatively maybe:
These two ways might not be ideal but probably work already for a large number of cases including the example in the question.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With