kcc icon indicating copy to clipboard operation
kcc copied to clipboard

Rainbow effect on grays on Kindle Colorsoft after converting with KCC

Open oncpnda opened this issue 1 year ago • 9 comments

I've noticed that some grays have a rainbow effect on the Kindle Colorsoft. This doesn't ruin the experience, but it can be distracting.

I compared the same frame to a version from Amazon's official release and the rainbow effect on the Amazon version isn't as prominent. This issue happens with all compression settings (JPEG/PNG/mozJpeg)

Is there something wrong with my settings, or is this caused by something in the conversion process?

Here are my settings (6.2.1):

Screenshot 2024-11-04 at 9 28 18 PM

KCC version: IMG_8841

Amazon version: IMG_8843

Pictures taken with iPhone 16 Pro.

Thanks again.

oncpnda avatar Nov 05 '24 03:11 oncpnda

You may want to bring this up in a forum where more people can comment like MobileRead or Reddit since I don't have a CS12.

But it could be anything. Color eink has limitations with grayscales and screentones.

I've also heard that kindle cs12 has different color modes like "vivid" that I'm unsure are available for mobi manga. Amazon manga is KFX.

axu2 avatar Nov 05 '24 03:11 axu2

what does it look like if you deactivate color mode in the kcc settings?

bust4cap avatar Nov 05 '24 11:11 bust4cap

Even with color mode deactivated, the grays have the rainbow effect. It is possibly just a limitation of the CS? Maybe I got one of the bad ones...

oncpnda avatar Nov 06 '24 02:11 oncpnda

@oncpnda is there a rendering mode toggle for vivid mode anywhere in the menu or Aa menu or control center via swipe from top of screen in book?

Rainbow sheen happens since color eink is just a normal bw panel behind a bunch of small red/blue/green stickers.

axu2 avatar Nov 06 '24 03:11 axu2

Yes, I forgot to mention in the initial post that it happens with both vivid and standard mode on low and high brightness.

oncpnda avatar Nov 06 '24 03:11 oncpnda

It's pretty much a property of color eink.

  • https://github.com/koreader/koreader/issues/11877

Interesting solutions discussed their. Blurring the image, using a profile with a smaller resolution, etc. I wonder if pw11 or scribe profile fixes it. @oncpnda

Maybe png would help? But png has a bug where it converts really slow rn.

  • #533

axu2 avatar Nov 06 '24 03:11 axu2

It is not a bug but another kindlegen limitation. If image file is too big or use format not supported by it then it is converted again and in general break everything KCC do.

There are good reasons why JPEG is default output. Every time when kindlegen is working too long on EPUB created by KCC mean that input was faulty.

AcidWeb avatar Nov 06 '24 05:11 AcidWeb

@utopiafallen looks like koreader from above post found a solution better than blurring using Fourier transform in case you are interested

axu2 avatar Jun 08 '25 14:06 axu2

@utopiafallen looks like koreader from above post found a solution better than blurring using Fourier transform in case you are interested

Hi, thanks for quoting my work :).

Sadly I do not have the knowledge nor the time to port my C code to python, but I'm sure it is doable with pyFFTW. I prefer an "on-the-fly" fix for the rainbow effect but for those who don't use Koreader and prefer fixing it when converting through KCC, this could be a starting point: https://github.com/Its-my-right/pocketbook_cfa_interference_breaker

Its-my-right avatar Jun 11 '25 16:06 Its-my-right

@axu2 Transforming into frequency domain and removing peaks would be low-pass filtering, and in the spatial domain, that would be a blur. The referenced method is equivalent to blurring the whole image in a way that reduces global and local contrast (the Pantheon article eliminates the peaks along the center horizontal and vertical axis which correspond to average image contrast in the horizontal and vertical axes), and you can see commenters explicitly having to fix that global contrast reduction by “re-normalizing” the resulting image.

All of this strikes me as a bit odd because the proposed solution to avoid blurring the image is….to the blur the image. If someone wants to implement this alternative blur, have at it, but I’d rather not pay the extra processing time in KCC that I already spent a significant effort in improving 😂

utopiafallen avatar Jun 29 '25 07:06 utopiafallen

@axu2 Transforming into frequency domain and removing peaks would be low-pass filtering, and in the spatial domain, that would be a blur. The referenced method is equivalent to blurring the whole image in a way that reduces global and local contrast (the Pantheon article eliminates the peaks along the center horizontal and vertical axis which correspond to average image contrast in the horizontal and vertical axes), and you can see commenters explicitly having to fix that global contrast reduction by “re-normalizing” the resulting image.

All of this strikes me as a bit odd because the proposed solution to avoid blurring the image is….to the blur the image. If someone wants to implement this alternative blur, have at it, but I’d rather not pay the extra processing time in KCC that I already spent a significant effort in improving 😂

Please see for yourself:

Vanilla Picture Image

KCC 7.6.0 Blurred picture: Image

Fourier Picture: Image

Both methods involve some form of blur, yes.

But the drawings and text are sharper with the Fourier transform method. Furthermore, in this example, the settings are particularly aggressive (pushed to cover more than just rainbow effect removal: they also include the "smoothing" of certain patterns). With settings limited to rainbow effect removal, the image would have a sharpness closer to the original image.

I completely understand that you don't want to rewrite a feature that you consider sufficient as it stands. I myself don't really have the time or the expertise to contribute to an open-source project. But I wanted to share my work here because I thought it might be of interest to some users bothered by blur.

However, I remain convinced that "fixing" the rainbow effect by altering the image isn't the best option: source images shouldn't suffer a loss of quality just to compensate for a hardware problem due to the screen. I prefer the on-the-fly patch method that doesn't alter the original images, which is why I also presented this work on the koreader GitHub. But I imagine that some users use their e-reader's internal reader and not koreader, and for them, altering the source images is the only option.

Its-my-right avatar Jun 29 '25 18:06 Its-my-right

At the risk of overfitting for a specific test case, you can more or less recreate the Fourier transform results by tweaking the parameters currently used by KCC to apply the rainbow reduction:

def optimizeForDisplay(self):
        # Reduce rainbow artifacts for grayscale images by breaking up dither patterns that cause Moire interference with color filter array
        if (self.opt.displayType == DisplayType.KALEIDO3_COLOR and not self.color):
            unsharpFilter = ImageFilter.UnsharpMask(radius=1, percent=25)
            self.image = self.image.filter(unsharpFilter)
            self.image = self.image.filter(ImageFilter.BoxBlur(0.25))
            self.image = self.image.filter(unsharpFilter)

And here is the result: Image (I disabled resizing and auto-contrast in KCC since that makes the visual comparison more difficult.)

As a bonus, this avoids some of the aliasing artifacts introduced by the Fourier transform (you can see it as noise inside the white text) that I'm guessing is happening because globally rejecting frequency peaks means that some signals will be undersampled and can't be correctly represented anymore when transformed back (e.g. clean vertical and horizontal edges). This aliasing noise still ends up being aesthetically pleasing because it's perceived as detail, similar to film grain, which also enhances the perception of sharpness.

Anyway, this was mostly an academic exercise to prove to myself my own intuition that there isn't something inherently unique to blurring in the frequency domain that couldn't be represented in the spatial domain. I'm happy there are multiple solutions out there for hiding the rainbow artifacts on these Kaleido 3 screens.

utopiafallen avatar Jun 30 '25 20:06 utopiafallen

At the risk of overfitting for a specific test case, you can more or less recreate the Fourier transform results by tweaking the parameters currently used by KCC to apply the rainbow reduction:

def optimizeForDisplay(self): # Reduce rainbow artifacts for grayscale images by breaking up dither patterns that cause Moire interference with color filter array if (self.opt.displayType == DisplayType.KALEIDO3_COLOR and not self.color): unsharpFilter = ImageFilter.UnsharpMask(radius=1, percent=25) self.image = self.image.filter(unsharpFilter) self.image = self.image.filter(ImageFilter.BoxBlur(0.25)) self.image = self.image.filter(unsharpFilter) And here is the result: Image (I disabled resizing and auto-contrast in KCC since that makes the visual comparison more difficult.)

As a bonus, this avoids some of the aliasing artifacts introduced by the Fourier transform (you can see it as noise inside the white text) that I'm guessing is happening because globally rejecting frequency peaks means that some signals will be undersampled and can't be correctly represented anymore when transformed back (e.g. clean vertical and horizontal edges). This aliasing noise still ends up being aesthetically pleasing because it's perceived as detail, similar to film grain, which also enhances the perception of sharpness.

Anyway, this was mostly an academic exercise to prove to myself my own intuition that there isn't something inherently unique to blurring in the frequency domain that couldn't be represented in the spatial domain. I'm happy there are multiple solutions out there for hiding the rainbow artifacts on these Kaleido 3 screens.

Which color e-reader do you have? And have you tried displaying your latest image on it? Because when I display that image on my InkPad Color 3, which has the same resolution as the image, the rainbow effect is still visible (less than in the original image, of course, but still distracting).

Regarding the comparison of methods, you're right when you say that everything that can be done in the frequency domain can also be done in the spatial domain. This is mathematically true according to the convolution theorem.

However, for this specific use case, since the interferences causing the rainbow effect appear as localized peaks in the Fourier domain, acting precisely on those peaks is a more "surgical" and less "global" way to remove the root cause—and only that. In theory, this makes it possible to eliminate only the unwanted frequencies while preserving the rest of the image. It's easier to isolate frequency peaks in the frequency domain than in the spatial domain.

That said, my localized frequency suppression algorithm is far from optimal and could be significantly improved. It works in its current state and produces results that I find very satisfying, but there is still plenty of room for improvement.

Thanks to our exchanges, I’ve decided to modify my frequency suppression algorithm to specifically match the spatial frequency of the Kaleido 3 CFA. Since this frequency may vary slightly from one unit to another, it will require a preliminary test: displaying calibration patterns tuned to different frequencies to determine at which cycles-per-pixel value the patterns cause rainbow artifacts. That value could then be entered as a parameter in the algorithm, which will then target that specific frequency range for attenuation, instead of simply removing all frequency "peaks". The result should be precise and tailored to each individual screen—suppressing only the problematic parts specific to that display while keeping the rest of the image untouched.

I'm also glad that there are several ways to tackle this problem. I always find it cool when users work to fix issues that manufacturers haven’t managed to solve. I hope someone will eventually find an even better way to eliminate the rainbow effect—whether in the spatial or frequency domain :)

Its-my-right avatar Jul 01 '25 18:07 Its-my-right

Just to jump in with my own anecdote: I implemented the modified optimizeForDisplay function and while there was still some rainbow effect on grays when viewed on my Colorsoft, compared to the function that ships in the compiled version it was a much better compromise in regards to how blurry the text gets. Thank you @utopiafallen.

gardinermichael avatar Jul 01 '25 23:07 gardinermichael

Sure, happy to help! And I would suggest keep playing with different strengths for the unsharp mask and different radius value for the box blur since you're still getting the rainbow artifacts. I suspect that the box blur radius probably needs to go up to 0.5 or 0.75, in which case you'll want to make the second unsharp stronger to restore some of the sharpness.

On Tue, Jul 1, 2025 at 4:59 PM Michael Gardiner @.***> wrote:

gardinermichael left a comment (ciromattia/kcc#771) https://github.com/ciromattia/kcc/issues/771#issuecomment-3025878271

Just to jump in with my own anecdote: I implemented the modified optimizeForDisplay function and while there was still some rainbow effect on grays when viewed on my Colorsoft, compared to the function that ships in compiled version it was a much better compromise in regards to how blurry the text gets. Thank you @utopiafallen https://github.com/utopiafallen.

— Reply to this email directly, view it on GitHub https://github.com/ciromattia/kcc/issues/771#issuecomment-3025878271, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOT7JKOASIKZDRAABT46UT3GMOHPAVCNFSM6AAAAABRFTJBPSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTAMRVHA3TQMRXGE . You are receiving this because you were mentioned.Message ID: @.***>

utopiafallen avatar Jul 02 '25 02:07 utopiafallen

OK, I've finished refining my rainbow effect frequency removal algorithm! By displaying many different patterns on Kaleido 3, it appears that the CFA is oriented at approximately 135° and that several frequencies, particularly around 0.16, 0.32, and 0.40->0.50 cycles/pixel, interfere with the CFA, creating rainbow effect artifacts.

Rather than removing high frequencies in all directions, I modified the algorithm to strongly attenuate the magnitude of key frequencies (within a tolerance interval), oriented around 135° (also within a tolerance interval), leaving all other frequencies/directions untouched.

The result is images without rainbow artifacts, and with much better sharpness than in my first version.

Additionally, I've also adapted my code so that it no longer reconstructs the Hermitian symmetry of the spectrum after the FFT, which improves processing time to around 300 ms :)

Here's the result for the same image after applying this new method:

Image

Its-my-right avatar Jul 06 '25 09:07 Its-my-right

Awesome, now that actually sounds like an improvement over a global blur!

On Sun, Jul 6, 2025, 2:17 AM Its-my-right @.***> wrote:

Its-my-right left a comment (ciromattia/kcc#771) https://github.com/ciromattia/kcc/issues/771#issuecomment-3041236260

OK, I've finished refining my rainbow effect frequency removal algorithm! By displaying many different patterns on Kaleido 3, it appears that the CFA is oriented at approximately 135° and that several frequencies, particularly around 0.16, 0.32, and 0.40->0.50 cycles/pixel, interfere with the CFA, creating rainbow effect artifacts.

Rather than removing high frequencies in all directions, I modified the algorithm to strongly attenuate the magnitude of key frequencies (within a tolerance interval), oriented around 135° (also within a tolerance interval).

The result is images without rainbow artifacts, and with much better sharpness than in my first version.

Additionally, I've also adapted my code so that it no longer reconstructs the Hermitian symmetry of the spectrum after the FFT, which improves processing time to around 300 ms :)

Here's the result for the same image after applying this new method: 04.-.fourier_new_2.png (view on web) https://github.com/user-attachments/assets/251d8ce6-0e2a-4d59-939f-07101e6ad137

— Reply to this email directly, view it on GitHub https://github.com/ciromattia/kcc/issues/771#issuecomment-3041236260, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOT7JPDGMMSLHZ5ZRP3UYD3HDSSFAVCNFSM6AAAAABRFTJBPSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTANBRGIZTMMRWGA . You are receiving this because you were mentioned.Message ID: @.***>

utopiafallen avatar Jul 06 '25 16:07 utopiafallen

I made my first ever pull request, covering this :) https://github.com/ciromattia/kcc/pull/1027

Its-my-right avatar Jul 12 '25 13:07 Its-my-right

@Its-my-right now that's cool. Btw, is this algorithm modifiable to handle normal b/w moire on bw eink?

axu2 avatar Jul 12 '25 14:07 axu2

@Its-my-right now that's cool. Btw, is this algorithm modifiable to handle normal b/w moire on bw eink?

I think it could be. For B/W moiré the solution would probably be to attenuate high frequencies as well (>= 0.3 cycles/pixel). For the rainbow effect, targeting high frequencies in the 135° direction (with a margin) is effective because the CFA is oriented at 135° on Kaleido 3. Now for the B/W moiré, we would need to check if it occurs more often in particular directions (I don't know manga tones well) and target those directions. If no particular direction is identifiable, we can still attenuate high frequencies in all directions, but this would be roughly equivalent to utopiafallen's solution (with a slightly longer processing time).

Its-my-right avatar Jul 12 '25 14:07 Its-my-right

Just in case it's useful, I found this paper on moire reduction:

http://hdl.handle.net/10919/30304

I may need to open a new issue since b/w moire is separate but related issue.

I think the important part is:

Chapter 9 Prevention of Moire Patterns When Sampling a Halftone

An aliasing moire pattern in a sampled halftone image is due to insufficient low-pass filtering prior to sampling. If we can perform proper low-pass filtering, we can prevent aliasing moire altogether.

The partial inverse Fourier transform method converts an image of M ×N pixels to a lower resolution image of m×n pixels, m≤M, n≤N.

By inverse transforming only the center portion of the Fourier transform of the input image, a uniform subsampling preceded by an ideal low-pass filtering is implicitly performed on the input image. No aliasing occurs in the output image.

axu2 avatar Jul 12 '25 23:07 axu2

Just in case it's useful, I found this paper on moire reduction:

http://hdl.handle.net/10919/30304

I may need to open a new issue since b/w moire is separate but related issue.

I think the important part is:

Chapter 9 Prevention of Moire Patterns When Sampling a Halftone

An aliasing moire pattern in a sampled halftone image is due to insufficient low-pass filtering prior to sampling. If we can perform proper low-pass filtering, we can prevent aliasing moire altogether.

The partial inverse Fourier transform method converts an image of M ×N pixels to a lower resolution image of m×n pixels, m≤M, n≤N.

By inverse transforming only the center portion of the Fourier transform of the input image, a uniform subsampling preceded by an ideal low-pass filtering is implicitly performed on the input image. No aliasing occurs in the output image.

That seems to be indeed an (old but) interesting source. As you said I think moire pattern reduction is indeed a related but distinct issue. Do you have source files and pictures of how they display on a reader ? I may dig into this sometime, could be a good starting point

Its-my-right avatar Jul 13 '25 01:07 Its-my-right

I am looking for volunteers to test the new rainbow effect removing algorithm on their e-reader.

I have noticed at least two different CFA orientations on two e-reader models (135° on Pocketbook Inkpad Color 3 with Kaleido 3 7.8" screen and 45° on Kobo Libra Color with Kaleido 3 7" screen).

The idea is to gather data to determine the precise CFA orientation depending on the e-reader model (it is possible that all Kaleido 3 of the same size have the same CFA orientation because they are all produced by the same company, but production methods may have changed over time or according to which e-reader manufacturers it goes).

This would then make the algorithm more accurate.

Two test builds are available in my repo:

(Edited - axu2) https://github.com/axu2/kcc/releases/tag/v8.0.4-major https://github.com/axu2/kcc/releases/tag/v8.0.4-minor

Testing is simple: Choose a manga that displays a rainbow effect on your e-reader after being converted with KCC, and convert it with the 8.0.4+ build. If the converted manga still displays a rainbow effect on your e-reader, follow the same process but with the 8.0.4+b build.

Then, please just share your results here:

  • Which of the two builds removes the rainbow effect (don't bother the angle thing, the name of the build 8.0.4+ / 8.0.4+b is enough ;))
  • Which e-reader you tested this on

Thank you!

Its-my-right avatar Jul 14 '25 23:07 Its-my-right

I am looking for volunteers to test the new rainbow effect removing algorithm on their e-reader.

Then, please share your results here:

  • Which of the two builds removes the rainbow effect
  • Your e-reader's reference

Thank you!

I would be happy to help with a Kindle Colorsoft, but how I would be able to find the CFA degree/reference?

gardinermichael avatar Jul 14 '25 23:07 gardinermichael

You just tell us which build fixes the problem and that will tell us the angle. @gardinermichael

I think by reference he just means tell us which device model you have.

axu2 avatar Jul 14 '25 23:07 axu2

Yeah sorry my English is rusty ! I updated my comment, it should be clearer

Its-my-right avatar Jul 15 '25 00:07 Its-my-right

Turns out those test builds don't run, I rebuilt them with fixed imports

https://github.com/axu2/kcc/releases/tag/v8.0.4-major https://github.com/axu2/kcc/releases/tag/v8.0.4-minor

axu2 avatar Jul 15 '25 04:07 axu2

Disabled: Image New method: Image Old method: Image

axu2 avatar Jul 15 '25 05:07 axu2

Kindle Colorsoft running 5.18.3

No Rainbow Blur image

Old Rainbow Blur image

Major image

Minor image

Apologies for the warm tone, forgot to turn that off, but it's made a huge difference! Great work 👏! I'm not sure how easy it is to tell from the pictures but the Major/8.0.4+ branch has got rid of the rainbow effect entirely while maintaining most of the text crispness. The Minor/8.0.4+b branch seems to still have the rainbow effect. I would be happy to take more zoomed in pictures or retake the pictures without the warm tone if you would like.

gardinermichael avatar Jul 15 '25 06:07 gardinermichael

@oncpnda @KeePach @lovesewerrats @SUM1-UNO @nodscrim @Treishpel @

In case you want to test the new sharper rainbow eraser algorithm.

axu2 avatar Jul 16 '25 14:07 axu2