image-quantization icon indicating copy to clipboard operation
image-quantization copied to clipboard

Black/White dithering

Open mpp opened this issue 6 years ago • 3 comments

Hi, I'm not sure if this is an issue. Probably only my ignorance.

I want to apply a dithering algorithm to an image that come from an input (code as an angular component):

@Component({
  selector: "graphics-form",
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
      <div>
        <button mat-stroked-button color="primary" (click)="fileInput.click()">
          Upload
        </button>
        <input hidden type="file" #fileInput (change)="onFileChange($event)" />
      </div>
  `
})
export class GraphicsFormComponent {

  onFileChange(event) {
    if (event.target.files && event.target.files.length) {
      var img = new Image();
      img.onload = function() {
        const canvas: HTMLCanvasElement = document.createElement("canvas");
        canvas.height = img.height;
        canvas.width = img.width;
        const ctx = canvas.getContext("2d");
        ctx.drawImage(img, 0, 0);
        URL.revokeObjectURL(img.src);
        console.log(
          "the image is drawn",
          img.width,
          img.height,
          canvas.width,
          canvas.height
        );

        const pointContainer = iq.utils.PointContainer.fromHTMLCanvasElement(
          canvas
        );
        const distanceCalculator = new iq.distance.EuclideanBT709();
        const paletteQuantizer = new iq.palette.WuQuant(distanceCalculator, 2);
        paletteQuantizer.sample(pointContainer);
        const palette = paletteQuantizer.quantizeSync();
        console.log(palette);

        const imageQuantizer = new iq.image.ErrorDiffusionArray(
          distanceCalculator,
          iq.image.ErrorDiffusionArrayKernel.Jarvis
        );
        const outPointContainer = imageQuantizer.quantizeSync(
          pointContainer,
          palette
        );
        var uint8array = outPointContainer.toUint8Array();

        console.log(uint8array);
      };
      img.src = URL.createObjectURL(event.target.files[0]);
    }
  }
}

The palette contains 2 points (colors?): _pointArray: Array(2) 0: Point {uint32: 85133568, a: 5, b: 19, g: 9, r: 0, …} 1: Point {uint32: 4104476424, a: 244, b: 165, g: 87, r: 8, …} length: 2

Is the method correct? How should I proceed? I would like to have only black/white pixels. Should I iterate the canvas pixels and substitute with black each time I find (a: 5, b: 19, g: 9, r: 0) and with white each time I find (a: 244, b: 165, g: 87, r: 8)?

Thanks!

mpp avatar Feb 13 '19 20:02 mpp

I saw that setting the palette manually I get what I was looking for:

palette.add(iq.utils.Point.createByRGBA(0, 0, 0, 255)); // black
palette.add(iq.utils.Point.createByRGBA(255, 255, 255, 0)); // white

but why the Alpha channel of white has to be zero? If I set to 255 the result is wrong (or at least not what I expect).

mpp avatar Feb 13 '19 21:02 mpp

I'm having an issue that I think is related. When I generate a palette from an image it correctly limits the number of colors to what I specify when creating the palette quantizer. However, if I then add dithering, it completely ignores the target number of colors. Is there a way to limit the total number of colors used including after dithering?

gretchen-blackwood avatar Jan 21 '20 14:01 gretchen-blackwood

Quantizer: WuQuant Color distance: EuclideanBT709 Dithering: Jarvis

Palette with alpha = 255 for white color:

  palette = new iq.utils.Palette();
  palette.add(iq.utils.Point.createByRGBA(0, 0, 0, 255))
  palette.add(iq.utils.Point.createByRGBA(255, 255, 255, 255))

image

Palette with alpha = 0 for white color:

  palette = new iq.utils.Palette();
  palette.add(iq.utils.Point.createByRGBA(0, 0, 0, 255))
  palette.add(iq.utils.Point.createByRGBA(255, 255, 255, 0))

image

Demo app where to put these changes:

https://github.com/ibezkrovnyi/image-quantization/blob/45ca880ec8b8fb8cb96d0e863cdea4adb1df214c/packages/demo/src/controller/usage.ts#L115

How to run:

https://github.com/ibezkrovnyi/image-quantization/blob/45ca880ec8b8fb8cb96d0e863cdea4adb1df214c/packages/demo/package.json#L31

Summary:

Looks like alpha=255 (as expected) for white color gives best results.

Note: for images without alpha channel with alpha=0 for white color in palette the above settings give empty black box. Changing to Manhatten gives better results, however because one of the colors in palette now has alpha 0 - final result now depends on background color.

Please test first in demo app and then please let me know if it is still an issue.

ibezkrovnyi avatar Sep 12 '21 08:09 ibezkrovnyi