Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean background #107

Closed
wants to merge 4 commits into from
Closed

Clean background #107

wants to merge 4 commits into from

Conversation

zdenop
Copy link
Collaborator

@zdenop zdenop commented Dec 20, 2024

Improve background handling

@zdenop zdenop mentioned this pull request Dec 20, 2024
@zvezdochiot
Copy link
Contributor

zvezdochiot commented Dec 20, 2024

Hi @zdenop .

Wrong:

#define BW_THRESHOLD_DEF 192

See:

#define BW_THRESHOLD_DEF 128

if normalize bg, and:

  bwthresdelta = (bgnmode) ? 0 : 64;
  bw_threshold = ((bw_threshold + bwthresdelta) < 256) ? (bw_threshold + bwthresdelta) : 255;

if clean bg (128 + 64 = 192).

git diff >my_changes.patch
diff --git a/src/jbig2.cc b/src/jbig2.cc
index 79816d4..343ef24 100644
--- a/src/jbig2.cc
+++ b/src/jbig2.cc
@@ -62,6 +62,7 @@ usage(const char *argv0) {
   fprintf(stderr, "  -t <threshold>: set classification threshold for symbol coder (def: %0.2f)\n", JBIG2_THRESHOLD_DEF);
   fprintf(stderr, "  -w <weight>: set classification weight for symbol coder (def: %0.2f)\n", JBIG2_WEIGHT_DEF);
   fprintf(stderr, "  -T <bw threshold>: set 1 bpp threshold (def: %d)\n", BW_THRESHOLD_DEF);
+  fprintf(stderr, "  -N --normalize: backgrond clean/normalize\n");
   fprintf(stderr, "  -r --refine: use refinement (requires -s: lossless)\n");
   fprintf(stderr, "  -O <outfile>: dump thresholded image as PNG\n");
   fprintf(stderr, "  -2: upsample 2x before thresholding\n");
@@ -213,9 +214,11 @@ int
 main(int argc, char **argv) {
   bool duplicate_line_removal = false;
   bool pdfmode = false;
+  bool bgnmode = false;
   float threshold = JBIG2_THRESHOLD_DEF;
   float weight = JBIG2_WEIGHT_DEF;
   int bw_threshold = BW_THRESHOLD_DEF;
+  int bwthresdelta = 0;
   bool symbol_mode = false;
   bool refine = false;
   bool up2 = false, up4 = false;
@@ -363,6 +366,12 @@ main(int argc, char **argv) {
       continue;
     }
 
+    if (strcmp(argv[i], "-N") == 0 ||
+        strcmp(argv[i], "--normalize") == 0) {
+      bgnmode = true;
+      continue;
+    }
+
     // engage auto thresholding
     if (strcmp(argv[i], "--auto-thresh") == 0 ||
         strcmp(argv[i], "-a") == 0 ) {
@@ -421,6 +430,9 @@ main(int argc, char **argv) {
   struct jbig2ctx *ctx = jbig2_init(threshold, weight, 0, 0, !pdfmode, refine ? 10 : -1);
   int pageno = -1;
 
+  bwthresdelta = (bgnmode) ? 0 : 64;
+  bw_threshold = ((bw_threshold + bwthresdelta) < 256) ? (bw_threshold + bwthresdelta) : 255;
+  
   int numsubimages=0, subimage=0, num_pages = 0;
   while (i < argc) {
     if (subimage==numsubimages) {
@@ -456,7 +468,7 @@ main(int argc, char **argv) {
     if (verbose)
       pixInfo(source, "source image:");
 
-    PIX *pixl, *gray, *pixt;
+    PIX *pixl, *gray, *adapt, *pixt;
     if ((pixl = pixRemoveColormap(source, REMOVE_CMAP_BASED_ON_SRC)) == NULL) {
       fprintf(stderr, "Failed to remove colormap from %s\n", argv[i]);
       return 1;
@@ -474,7 +486,11 @@ main(int argc, char **argv) {
         fprintf(stderr, "Unsupported input image depth: %d\n", pixl->d);
         return 1;
       }
-      Pix *adapt = pixBackgroundNormSimple(gray, NULL, NULL);
+      if (bgnmode) {
+          adapt = pixBackgroundNormSimple(gray, NULL, NULL);
+      } else {
+          adapt = pixCleanBackgroundToWhite(gray, NULL, NULL, 1.0, 90, 190);
+      }
       pixDestroy(&gray);
       if (up2) {
         pixt = pixScaleGray2xLIThresh(adapt, bw_threshold);

PS: I will not move to the main branch until it has a release with #define JBIG2_THRESHOLD_MAX 0.97f (my branch has a release with this limit). And while I'm not on the main branch, I can't do PR (unresolved conflicts).

@zdenop
Copy link
Collaborator Author

zdenop commented Dec 20, 2024

I always do PR from other than the main branch. With git gui I can easily to push it to my GH repo and GH automatically offers to create PR.

@zvezdochiot
Copy link
Contributor

zvezdochiot commented Dec 20, 2024

Hi @zdenop .

Hmm,,,

I can do a non-linear scaling for normalize/clean bg to match the threshold scale range {0..255}:

clean
    ^
255 |----------
    |         |
192 | ----    |
    |    |    |
  0 |____|____|______
    0    128  255    normalize
if (!bgnmode) {
  float bwt =  bw_threshold;
  bwt = 2.0f * bwt - 1.0f / 255.0f * bwt * bwt;
  bw_threshold = (int) (bwt + 0.5f); /* 0.5f for round */
}

No bwthresdelta is used, just a non-linear transition from one scale (normalize) to another (clean).

@DanBloomberg
Copy link
Collaborator

DanBloomberg commented Dec 20, 2024

Correct me if I'm wrong.
You want the option of either using a global threshold (as before all this adaptive stuff), or using the adaptive method.
You want a flag N to choose which type of thresholding is to be used.
You want a single input threshold parameter to work with both types of thresholding.
You want different default thresholds.
You want the default threshold for global to be 128 and the default for adaptive to be 192 (difference is 64)

That's all fine with me, except see below about choosing which type of thresholding.

Assuming that's what you want, this doesn't do it.
Do not use pixBackgroundNormSimple() for anything. It leaves the grayscale image in a condition where the background is about 190.
pixCleanBackgroundToWhite() is what you want for adaptive thresholding. It does the background normalization and then does a TRC to remap the pixel values.

Suggest:
Have adaptive thresholding be the default; use an input "-G" to signify the inferior global thresholding.
For global thresholding, don't do any adjustment of the grayscale image. You can uses pixClone() for that purpose in the code; e.g.,

if (global_threshold)
    adapt = pixClone(gray)
else
   adapt = pixCleanBackgroundToWhite(...)

@zvezdochiot
Copy link
Contributor

zvezdochiot commented Dec 20, 2024

@DanBloomberg , the picture is actually like this:

Having worked with global, local, hybrid and pre-filtered thresholds, I'm used to expressing the threshold as:

threshold = T + delta

, where T is either an image-calculated value for a global threshold, or a threshold map of the same size as the image for local thresholds. And the adjustment is made using the delta parameter.

The type of threshold where the value is set directly is “slightly” strange for different images without analyzing them.

That’s why I initially asked you about the tiled Otsu, which is implemented in your library. Because the threshold in jbig2enc present at that moment and its value were unsatisfactory for different images.

Such are the things. 😄

@DanBloomberg
Copy link
Collaborator

I understand your general approach.

We are trying to get something simple and satisfactory for jbig2. Simple both in implementation and in what it does, so the user understands the options and can easily follow the code if they want to.

I was fine with your initial reply to allow a threshold value with the adaptive method pixCleanBackgroundToWhite().
I also am fine with allowing a global threshold, even though it works poorly for many images, because for clean scans it will work ok and it is faster (see below).

We should make this simple. Here again is my proposal:

  • Adaptive method is default. Use flag (e.g., 'G') to use a global threshold instead. A reasonable argument for allowing a mode with a global threshold is that it is faster because you don't need to do the cleaning operation, and for clean scans it will do fine.
  • Default threshold for adaptive is 192. Default for global is 128.
  • The input parameter 'T' can be used to change the threshold for either type.

That's it. No deltas required.

@zvezdochiot
Copy link
Contributor

zvezdochiot commented Dec 20, 2024

@DanBloomberg , this topic requires further discussion. And testing!

In the meantime, sufficient testing has not been carried out, this PR is finished (IMHO), but the discussion is not finished. And for discussion, testing is needed, and it is desirable that this testing be tied to a specific release that you can point your finger at.

And then there will be other releases...

PS: And all my reasoning has long gone beyond the scope of this PR.

Such are the things. 😄

@DanBloomberg
Copy link
Collaborator

You are right. This PR is not the final, optimal solution, but as I outlined, it is a very big advance over the current implementation.

So let's do it the way I suggested, adding one more command line flag to distinguish between global and adaptive thresholding. We can refine later based on more testing.

And consider this: if someone wants the absolute best results, both in the stored image and the compression, they'll need to do the kind of preprocessing that you do with your programs, including using the djvu classifier. Then the images presented to jbig2 will be optimal and won't need anything more than global thresholding.

@zvezdochiot
Copy link
Contributor

zvezdochiot commented Dec 20, 2024

@DanBloomberg . Both true and false at the same time. If everything were like this, then jbig2enc would immediately set a condition on monochrome images at the input, just like minidjvu does. And this would probably be correct, but for some reason it is not so. I don’t see any point in the new flag, because this is an optional return to release 0.29, which has been tested many times and this approach has been recognized (at least by me) as unsatisfactory.

Good luck. 😄

@DanBloomberg
Copy link
Collaborator

Having a single global threshold is unsatisfactory in general, but as I said, it is fine for sufficiently clean grayscale images.

Goal here: we're trying to improve the current situation (release 0.29 + a few changes), not going for an optimal solution, which as you said would tailor the processing based on an analysis of the images.

So let's do that. It's true that this puts more responsibility on the user to know what they are doing. But by making adaptive thresholding the default, it lessens the risk of getting release 0.29's bad behavior on difficult images We can fix jbig2 to automatically do a much better job, using adaptive thresholding with those iimages. I'll resend a jbig2.cc file that seems to do it.

@zvezdochiot
Copy link
Contributor

zvezdochiot commented Dec 20, 2024

@DanBloomberg .say:

Having a single global threshold is unsatisfactory in general, but as I said, it is fine for sufficiently clean grayscale images.

No. It makes sense only (only!) to speed up the encoding of BW images. No shades of gray. In this case, there is truth. If you encode prepared images, acceleration makes sense.

I'll try to make a patch. 😄

git diff >my_changes.patch
diff --git a/src/jbig2.cc b/src/jbig2.cc
index 79816d4..5ee600c 100644
--- a/src/jbig2.cc
+++ b/src/jbig2.cc
@@ -62,6 +62,8 @@ usage(const char *argv0) {
   fprintf(stderr, "  -t <threshold>: set classification threshold for symbol coder (def: %0.2f)\n", JBIG2_THRESHOLD_DEF);
   fprintf(stderr, "  -w <weight>: set classification weight for symbol coder (def: %0.2f)\n", JBIG2_WEIGHT_DEF);
   fprintf(stderr, "  -T <bw threshold>: set 1 bpp threshold (def: %d)\n", BW_THRESHOLD_DEF);
+  fprintf(stderr, "  -G --global: simply threshold for BW images\n");
+  fprintf(stderr, "  -N --normalize: background clean/normalize\n");
   fprintf(stderr, "  -r --refine: use refinement (requires -s: lossless)\n");
   fprintf(stderr, "  -O <outfile>: dump thresholded image as PNG\n");
   fprintf(stderr, "  -2: upsample 2x before thresholding\n");
@@ -213,9 +215,12 @@ int
 main(int argc, char **argv) {
   bool duplicate_line_removal = false;
   bool pdfmode = false;
+  bool bgnmode = false;
+  bool globalmode = false;
   float threshold = JBIG2_THRESHOLD_DEF;
   float weight = JBIG2_WEIGHT_DEF;
   int bw_threshold = BW_THRESHOLD_DEF;
+  int bwthresdelta = 0;
   bool symbol_mode = false;
   bool refine = false;
   bool up2 = false, up4 = false;
@@ -363,6 +368,18 @@ main(int argc, char **argv) {
       continue;
     }
 
+    if (strcmp(argv[i], "-G") == 0 ||
+        strcmp(argv[i], "--global") == 0) {
+      globalmode = true;
+      continue;
+    }
+
+    if (strcmp(argv[i], "-N") == 0 ||
+        strcmp(argv[i], "--normalize") == 0) {
+      bgnmode = true;
+      continue;
+    }
+
     // engage auto thresholding
     if (strcmp(argv[i], "--auto-thresh") == 0 ||
         strcmp(argv[i], "-a") == 0 ) {
@@ -392,7 +409,7 @@ main(int argc, char **argv) {
       if (t_dpi <= 0 || t_dpi > 9600) {
         fprintf(stderr, "Invalid dpi: (1..9600)\n");
         return 12;
-      } 
+      }
       dpi = (int)t_dpi;
       i++;
       continue;
@@ -421,6 +438,11 @@ main(int argc, char **argv) {
   struct jbig2ctx *ctx = jbig2_init(threshold, weight, 0, 0, !pdfmode, refine ? 10 : -1);
   int pageno = -1;
 
+  if (!globalmode) {
+    bwthresdelta = (bgnmode) ? 0 : 64;
+    bw_threshold = ((bw_threshold + bwthresdelta) < 256) ? (bw_threshold + bwthresdelta) : 255;
+  }
+
   int numsubimages=0, subimage=0, num_pages = 0;
   while (i < argc) {
     if (subimage==numsubimages) {
@@ -456,7 +478,7 @@ main(int argc, char **argv) {
     if (verbose)
       pixInfo(source, "source image:");
 
-    PIX *pixl, *gray, *pixt;
+    PIX *pixl, *gray, *adapt, *pixt;
     if ((pixl = pixRemoveColormap(source, REMOVE_CMAP_BASED_ON_SRC)) == NULL) {
       fprintf(stderr, "Failed to remove colormap from %s\n", argv[i]);
       return 1;
@@ -474,7 +496,13 @@ main(int argc, char **argv) {
         fprintf(stderr, "Unsupported input image depth: %d\n", pixl->d);
         return 1;
       }
-      Pix *adapt = pixBackgroundNormSimple(gray, NULL, NULL);
+      if (globalmode) {
+        adapt = pixClone(gray);
+      } else if (bgnmode) {
+        adapt = pixBackgroundNormSimple(gray, NULL, NULL);
+      } else {
+        adapt = pixCleanBackgroundToWhite(gray, NULL, NULL, 1.0, 90, 190);
+      }
       pixDestroy(&gray);
       if (up2) {
         pixt = pixScaleGray2xLIThresh(adapt, bw_threshold);
@@ -583,4 +611,3 @@ main(int argc, char **argv) {
   return 0;
 
 }
-

@DanBloomberg
Copy link
Collaborator

Not just BW. Skipping local thresholding and using a global threshold also makes sense for clean 8 bpp images, however they have been produced.

@zdenop
Copy link
Collaborator Author

zdenop commented Dec 21, 2024

So what is the staus? Can this be merged into the main and can we proceed to the new release?

Copy link
Collaborator

@DanBloomberg DanBloomberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for jumping in!

This needs to be simplified.

  • remove the -N flag; we don't need it
  • remove the bgnmode (we have one mode variable, globalmode, that determines if we're using global or adaptive thresholding
  • remove bwthresdelta (not needed)
  • set bw_threshold to be default (global or adaptive) if no '-T' is used. Otherwise, use the '-T'. Range of allowable input thresholds is given by the MAX & MIN constants (we can refine later).

I'll try to send you a working example jbig2.cc later today.

Dan

@DanBloomberg
Copy link
Collaborator

DanBloomberg commented Dec 21, 2024

Here's the simplified version of jbig2.cc, as described above (etc).
Also the result for local and global, using default threshold values.
jbig2.cc.gz
local-default-result
global-default-result

@zvezdochiot
Copy link
Contributor

Hi all.

First, delete the image threshold parameter, then say that it is “not important” and then, without regaining consciousness, add a new parameter (second) for the same threshold adjustment.

This is all very bad. Users don't understand you.

But the main thing is that you understand yourself. You know better....

PS: Compromise is when the interests of all parties are taken into account. 😄

@zvezdochiot
Copy link
Contributor

zvezdochiot commented Dec 22, 2024

Hi all.

No matter how you wiggle, but testing is a necessary part of the process. And you won’t get away from this anywhere.

Origin

page-011

Current state of PR.

PDF Mode Screen
page-011-C-zvezdochiot.pdf clean screen-page-011-C-zvezdochiot
page-011-G-zvezdochiot.pdf global screen-page-011-G-zvezdochiot
page-011-N-zvezdochiot.pdf normalize screen-page-011-N-zvezdochiot

Patch by @DanBloomberg

PDF Mode Screen
page-011-C-dan.pdf clean screen-page-011-C-dan
page-011-G-dan.pdf global screen-page-011-G-dan

Good luck. 😄

@DanBloomberg
Copy link
Collaborator

A whole bunch of comments.

(1) Your representation of my "global" is wrong. It appears to be the same as your "global". With my patch:

./jbig2 -G -s /tmp/new-gray-2024.jpg > /tmp/global.jb2
 jbig2dec -o /tmp/global.png /tmp/global.jb2

yields the global that I showed, which isn't terrible. I do not know the reason for the difference.
The code path is very simple:

    pix1 = pixRead("new-gray-2024.jpg");
    pix2 = pixConvertRGBToGrayFast(pix1);
    pix3 = pixThresholdToBinary(pix2, 128);
    pixDisplay(pix3, 100, 100);

(2) You claim that my users don't understand me.
That's not my general experience, and in any event you are very much smarter than my average 'user'.

(3) We may have been talking past each other over the last few days, but I have tried to be as clear as possible about my suggestions.

(4) As I have said several times, one should not use the pixBackgroundNorm*() functions before thresholding, without first doing a reasonable TRC.

(5) The result from my patch on your image is far better than what we currently have in release 0.29.

(6) Keeping global thresholding was actually your suggestion (I was initially ready to drop it), and I kept it for the reason I gave: that it gives the user a more efficient path they can use with clean images. Such as your cleaned up input images.

(7) We use adaptive thresholding by default because it is more robust, users generally value quality over processing time, and we want to give them quality first out of the box.

(8) Really, this is not a big deal. We're all adults here. Zdenko and I are just trying to make agl's project more useful for users, as you are. And as a user, you're not relying on our binarization for difficult images because you do all the cleaning in preprocesor stages using djvumini and your new programs.

@zvezdochiot
Copy link
Contributor

zvezdochiot commented Dec 22, 2024

Hi all.

Another option for discussion: simple and easy adjustment of scaling of the image threshold scale {0..255} for various modes (without any delta, only scaling). The default image threshold setting is 128 for all modes.

Mode Shift Curve
clean +0.5 (128~192) screen-plot-curve-C
global +0.0 (128~128) screen-plot-curve-G
normalize +0.125 (128~144) screen-plot-curve-N
git diff >my_changes.patch
diff --git a/src/jbig2.cc b/src/jbig2.cc
index 79816d4..becaba1 100644
--- a/src/jbig2.cc
+++ b/src/jbig2.cc
@@ -50,6 +50,8 @@
 #define BW_THRESHOLD_MIN 0
 #define BW_THRESHOLD_MAX 255
 #define BW_THRESHOLD_DEF 128
+#define BW_THRESHOLD_RESCALE_CLEAN 0.5f
+#define BW_THRESHOLD_RESCALE_NORM 0.125f
 
 static void
 usage(const char *argv0) {
@@ -62,6 +64,8 @@ usage(const char *argv0) {
   fprintf(stderr, "  -t <threshold>: set classification threshold for symbol coder (def: %0.2f)\n", JBIG2_THRESHOLD_DEF);
   fprintf(stderr, "  -w <weight>: set classification weight for symbol coder (def: %0.2f)\n", JBIG2_WEIGHT_DEF);
   fprintf(stderr, "  -T <bw threshold>: set 1 bpp threshold (def: %d)\n", BW_THRESHOLD_DEF);
+  fprintf(stderr, "  -G --global: simply threshold for BW images\n");
+  fprintf(stderr, "  -N --normalize: background clean/normalize\n");
   fprintf(stderr, "  -r --refine: use refinement (requires -s: lossless)\n");
   fprintf(stderr, "  -O <outfile>: dump thresholded image as PNG\n");
   fprintf(stderr, "  -2: upsample 2x before thresholding\n");
@@ -213,6 +217,8 @@ int
 main(int argc, char **argv) {
   bool duplicate_line_removal = false;
   bool pdfmode = false;
+  bool bgnmode = false;
+  bool globalmode = false;
   float threshold = JBIG2_THRESHOLD_DEF;
   float weight = JBIG2_WEIGHT_DEF;
   int bw_threshold = BW_THRESHOLD_DEF;
@@ -363,6 +369,18 @@ main(int argc, char **argv) {
       continue;
     }
 
+    if (strcmp(argv[i], "-G") == 0 ||
+        strcmp(argv[i], "--global") == 0) {
+      globalmode = true;
+      continue;
+    }
+
+    if (strcmp(argv[i], "-N") == 0 ||
+        strcmp(argv[i], "--normalize") == 0) {
+      bgnmode = true;
+      continue;
+    }
+
     // engage auto thresholding
     if (strcmp(argv[i], "--auto-thresh") == 0 ||
         strcmp(argv[i], "-a") == 0 ) {
@@ -392,7 +410,7 @@ main(int argc, char **argv) {
       if (t_dpi <= 0 || t_dpi > 9600) {
         fprintf(stderr, "Invalid dpi: (1..9600)\n");
         return 12;
-      } 
+      }
       dpi = (int)t_dpi;
       i++;
       continue;
@@ -421,6 +439,24 @@ main(int argc, char **argv) {
   struct jbig2ctx *ctx = jbig2_init(threshold, weight, 0, 0, !pdfmode, refine ? 10 : -1);
   int pageno = -1;
 
+  /* Rescale BW threshold scale [0..128..255] to:  *
+   * clean mode (+0.5 == 1/2): [0..192..255]       *
+   * normalize mode (+0.125 == 1/8): [0..144..255] */
+  if (!globalmode) {
+    float bwr = 0.0f;
+    if (bgnmode) {
+      bwr = BW_THRESHOLD_RESCALE_NORM; /* 0.125 -> 128 ~ 144 */
+    } else {
+      bwr = BW_THRESHOLD_RESCALE_CLEAN; /* 0.5 -> 128 ~ 192 */
+    }
+    float bwt =  bw_threshold;
+    float bwa1 = 1.0f + 2.0f * bwr;
+    float bwa2 = (2.0f * bwr) / 255.0f;
+    bwt = bwa1 * bwt - bwa2 * bwt * bwt;
+    bwt = (bwt < 0.0f) ? 0.0f : ((bwt < 255.0f) ? bwt : 255.0f); /* clipping*/
+    bw_threshold = (int) (bwt + 0.5f); /* 0.5f for round */
+  }
+
   int numsubimages=0, subimage=0, num_pages = 0;
   while (i < argc) {
     if (subimage==numsubimages) {
@@ -456,7 +492,7 @@ main(int argc, char **argv) {
     if (verbose)
       pixInfo(source, "source image:");
 
-    PIX *pixl, *gray, *pixt;
+    PIX *pixl, *gray, *adapt, *pixt;
     if ((pixl = pixRemoveColormap(source, REMOVE_CMAP_BASED_ON_SRC)) == NULL) {
       fprintf(stderr, "Failed to remove colormap from %s\n", argv[i]);
       return 1;
@@ -474,7 +510,13 @@ main(int argc, char **argv) {
         fprintf(stderr, "Unsupported input image depth: %d\n", pixl->d);
         return 1;
       }
-      Pix *adapt = pixBackgroundNormSimple(gray, NULL, NULL);
+      if (globalmode) {
+        adapt = pixClone(gray);
+      } else if (bgnmode) {
+        adapt = pixBackgroundNormSimple(gray, NULL, NULL);
+      } else {
+        adapt = pixCleanBackgroundToWhite(gray, NULL, NULL, 1.0, 90, 190);
+      }
       pixDestroy(&gray);
       if (up2) {
         pixt = pixScaleGray2xLIThresh(adapt, bw_threshold);
@@ -583,4 +625,3 @@ main(int argc, char **argv) {
   return 0;
 
 }
-

Rescale:

  • clean: +0.5 -> 128 ~ 192
  • global: +0.0 -> 128 ~ 128
  • normalize: +0.125 -> 128 ~ 144
PDF mode Screen
page-011-RC.pdf clean (+0.5) screen-page-011-RC
page-011-RG.pdf global (+0.0) screen-page-011-RG
page-011-RN.pdf normalize (+0.125) screen-page-011-RN

Good luck. 😄

@DanBloomberg
Copy link
Collaborator

I don't have much more to add. To recapitulate:

(1) your approach is overly complicated
(2) your 'scaling' of pixel values is one parameter of our 3-parameter TRC, which, as I said, must be used with background normalization.
(3) Background normalization with 3-parameter TRC, which we are doing here with local thresholding, has been extensively studied and tested, and the parameters I offered generally work well. By that I mean both that the results are pretty good and that the algorithm is robust: the results are not strongly dependent on the specific parameter values,
(4) If you want to make a significant contribution, you can bundle up your two very nice binarization programs into two functions that can be incorporated with leptonica, so that it's available for any applications using leptonica.

For now, let's proceed with my jbig2.cc, for all the reasons that I have previously given.

@zvezdochiot
Copy link
Contributor

zvezdochiot commented Dec 23, 2024

@zdenop , use @DanBloomberg patch. I wash my hands of the fact that the usual brightness curve, which is in every graphics editor, is difficult.

And make a release.

Good luck. 😄

@zdenop
Copy link
Collaborator Author

zdenop commented Dec 24, 2024

Closing in favor of 528a5f4. Thank you for your cooperation!
The new release was created. Let's improve it further!

@zdenop zdenop closed this Dec 24, 2024
@zdenop zdenop deleted the CleanBackground branch December 24, 2024 08:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants