Message Boards Message Boards

18
|
11616 Views
|
4 Replies
|
27 Total Likes
View groups...
Share
Share this post:

Cleaning whiteboard with (almost) four steps

Hi everybody, here is my first post on Wolfram Community

The idea presented here is inspired by whiteboardClean.sh script for ImageMagic. Let's suppose there is a whiteboard photo, like this
SetDirectory[NotebookDirectory[]]
initial = Import["Whiteboard.jpg"]

The algorithm should clean it thereby making a text more visible. I aim here to make a simple algorithm with a few (clearly undestood) parameters without fine tuning (like choosing a precise threshold for binarization). However, in order to make image processing efficient one usually needs some information a priori.

There are three initialization parameters:
thickness = 4;
denoising = 2;
enhancement = 4;
We assume that there are only lines/curves on the whiteboard and we know approximately the thickness of these lines. It is not necessary to know the thickness exactly it is rather a characteristic scale or an upper-bound estimate for it. There are a lot of methods to extract such scale from the image automatically, hence I take it as known. The meaning of other two parameters will be clear from the following. The first step is denoising:
image = ColorNegate@WienerFilter[initial, denoising];
The second step is to prepare a simple approximate mask for the text:
mask = Erosion[
   Composition[ColorNegate, DeleteSmallComponents, ColorNegate]@
    Dilation[EdgeDetect[ColorConvert[image, "GrayScale"], thickness + 1],
     thickness], thickness - 2];
Here is a demonstration how it works:
HighlightImage[initial, mask]

The third step is to prepare a background:
background =
  Inpaint[ImageMultiply[image, ColorNegate@mask], mask,
   Method -> "NavierStokes"];
The fourth step is to subtract the background and enhance colors:
result = Sharpen@
  ColorNegate@
   ImageMultiply[
    ImageSubtract[ImageMultiply[image, mask],
     ImageMultiply[background, mask]], enhancement]
POSTED BY: Grisha Kirilin
4 Replies
Ausgezeichnet, Grisha! I was faced with a similar problem not too long ago, and your method is much more complete and far surpasses my meager efforts. The method would work well for wrting on almost any medium, so I would imagine it would be very useful for cleaning up lecture notes, handwritten correspondence, etc. I'm wondering if a filter could be applied to remove the horizontal rules on typical notebook paper?

Bob
POSTED BY: Robert Nachbar
Hi Bob,

unfortunately, this method is useless for horizontal rules removal. But there is much more simple and efficent methods. Any periodic noise can be efficently removed by filtering in  frequency domain. You can read a very nice introduction be Prof. Philippe Cattin here.
Grisha
POSTED BY: Grisha Kirilin
I tried inpaiting for a very simple example with grid lines and as expected it doesn't work well:
SetDirectory[NotebookDirectory[]];
initial = Import["Notebook 2.jpg"]

Now it is much more difficult to design a robust algorithm. Here is a very stupid brutal force method. First, I need more parameters:
angle = 5;        (* threshold for horizontal lines *)
denoising = 1;    (* not important *)
thickness = 1;    (* approximate thickness of the lines *)
threshold = 0.95; (* not important *)
postprocessing = MeanShiftFilter[#, 4, .03, MaxIterations -> 10] &; (* important *)
Let's prepare black and white image:
image = ImageAdjust@
   ColorNegate@
    WienerFilter[ColorConvert[ImageAdjust@initial, "Grayscale"], 1];
The second step is to extract horizontal lines:
lines = ImageLines[image];
booleMask =
  Abs[#] < (angle Pi)/360 & /@
   ArcTan[Divide @@@ Composition[Reverse, Subtract] @@@ lines];
hlines = Pick[lines, booleMask];
The third step is to prepare a mask for inpainting:
imageWithLines =
  Rasterize[
   Show[initial,
    Graphics[{Black,
      Thickness[(thickness + 2)/First@ImageDimensions[initial]],
      Line /@ hlines}]], ImageSize -> ImageDimensions[initial]];
mask = Dilation[Binarize[ColorNegate[imageWithLines], threshold], 1];
The last step is inpainting and postprocessing:
result = postprocessing@
  Inpaint[ImageMultiply[initial, ColorNegate@mask] , mask ]
POSTED BY: Grisha Kirilin
This works very well - nice hob! I know Radon can be used to measure lines position and orientation in the image. I wonder if Radon can also be used to filter out the lines. Or, say, GradientOrientationFilter. I like the image btw - artistic and a bit poignant ;-)
POSTED BY: Sam Carrettie
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract