Decompose an image into better compressible components Our team develops an application that, in some feature, connects to a scanner (via TWAIN or WIA) and scans a document, and makes a PDF file out of it. The application is mostly used to process mail or documents with few images.

We recently noticed that the PDF files generated by our application are four times larger (speaking of file size) than those generated by the scanner software, although similar scanner parameters are used (resolution, color, etc).

So I delved into the generated pdf files and this is what I got:


With MuPDF component mutool.exe I got information about the objects inside the PDFs:


Our PDF contains one image (not surprising, it is made directly from the result of the scan):

[ DCT ]      3302x4668 8bpc DevRGB

The PDF file generated by the scanner software contains two images (aha!, this is more surprising), that differ in size and, that do not have the same color profile:  

[ DCT ]      1650x2334 8bpc DevRGB
[ CCITTFax ] 3176x4512 1bpc ImageMask


Still using mutool, I extracted the two images from the PDF generated by the scanner software:


The first image is what we could call the “Background”: here are a thumbnail of it, and a detail at 100% size:
 
The second image is a pure B&amp;W (1 bit per pixel) layer, with mostly black; here is a detail at 100% size:




So it appears that the software that the scanner comes with uses an algorithm that detects that the document is mostly black and white, and then decomposes the image in two parts that it overlays; the first part consists of small details that can be downsampled (and therefore take less space), and the second part consists of only black or white dots, and with which better compression can be achieved.

My question is: how can we do something similar?

Thanks
Assuming that the image is gray level (not color)


Use Otsu's thresholding method to detect whether the image has bi-modal histogram.
If Otsu tells you with high confidence that the image is bi-modal, use the threshold that it gave you in order to binarize the image. That is your binary mask that can be effectively packed into bits.
Find the gray values of the two histogram modes, create a mask where the "white" color is the gray value of the second mode and "black" color is the value of the first mode.
Subtract previously made mask from the image. These are your small changes that you can compress by using lossy compression.
Save the two modes as two integers together with the document.