Interpoloation algorithm for image smoothing - Angular 12 environment

147 views Asked by At

I am working on implementing a bicubic interpolation function (within our Angular application) in order to "smooth" an image upon zooming. Without it the image becomes very pixelated on zoom.

I have it working in the StackBlitz online project (https://stackblitz.com/edit/angular-ivy-bga9dz?file=src/app/app.component.ts), but NOT in our application -and I can't figure out why.

In this application code sample below - the mousewheel scroll event fires zoom(), which calls redraw().

In redraw(), I create a hidden canvas, put the bicubic results to it, then draw to main ctx0 canvas context. But the image is still pixelated, as if the results array has no affect.

handleScroll(that: ImageViewerComponent, evt: MouseWheel, fromAction?: boolean): boolean {
   that.zoom(delta, evt.offsetX, evt.offsetY);
}

zoom(clicks: number, mouseX: number, mouseY: number): void {
        const oldWidth: number = this.cw;
        const oldHeight: number = this.ch;

        this.totalClicks = this.totalClicks + clicks;

        const factor: number = Math.pow(this.scaleFactor, clicks);
        this.cx = this.sx + this.cw / 2; // current x
        this.cy = this.sy + this.ch / 2; // curreny y
        this.cw = this.cw * factor; // current width
        this.ch = this.ch * factor; // current height

        this.saveCX = this.cx;
        this.saveCY = this.cy;
        this.saveCW = this.cw;
        this.saveCH = this.ch;

        // Don't zoom if the image is either too small or too large.
        this.ctx0.setTransform(1, 0, 0, 1, 0, 0);

        // Coordinates of the mouse relative to the image, with the origin being the top-left.
        const relativeMouseX: number = mouseX - this.sx;
        const relativeMouseY: number = mouseY - this.sy;

        this.sx += (relativeMouseX / oldWidth) * (oldWidth - this.cw);
        this.sy += (relativeMouseY / oldHeight) * (oldHeight - this.ch);
        this.scaleX = this.cw / this.imageDimensions[0];
        this.scaleY = this.ch / this.imageDimensions[1];

        this.saveSX = this.sx;
        this.saveSY = this.sy;
        this.saveScaleX = this.scaleX;
        this.saveScaleY = this.scaleY;
        this.zoomSaved = true;

        this.redraw(true);
}
    
redraw(isZooming = false): void {

    this.clearStage(); // reassign the this.ctx0 context. run a clearRect()/setTransform()
    
    this.ctx0.drawImage(this.imageObj, this.sx, this.sy, this.cw, this.ch);

    if (this.imgType === 'bscan' && isZooming && this.useBicubicInterp) {
      const hiddenCanvas = document.createElement('canvas');
      hiddenCanvas.width = this.ctx0.canvas.width;
      hiddenCanvas.height = this.ctx0.canvas.height;
      this.ctxHiddenZoomCanvas = hiddenCanvas.getContext('2d');
      this.ctxHiddenZoomCanvas.setTransform(1, 0, 0, 1, 0, 0);

      const imageData = this.ctx0.getImageData(0, 0, this.canvasDimensions[0], this.canvasDimensions[1]);
      const dest = this.ctxHiddenZoomCanvas.createImageData(this.ctx0.canvas.width, this.ctx0.canvas.height);
      
      // BICUBIC CALL ! WRITE RESULTS TO CANVAS.
      let scale = 1.5;      
      const results = this.mediaService.bicubic(imageData, dest, scale);
      
      this.ctxHiddenZoomCanvas.putImageData(results, 0, 0);
      this.ctx0.drawImage(this.ctxHiddenZoomCanvas.canvas, this.sx, this.sy, this.cw, this.ch);
      }
    
}

Further details -

Normal image size (viewed in app, no smoothing, no zooming):

enter image description here

Zoomed in (via mouse wheel) and custom zooming code (canvas imageSmoothingEnabled = false) -

enter image description here

We have tested the Html5 Canvas smoothing with imageSmoothingEnabled, and it does remove the pixelation on zoom. However, since it's not clear what algorithm Chrome uses (perhaps bilinear), we would like to implement the more advanced bicubic interpolation on our images.

E.g. with Canvas imageSmoothingEnabled=true, quality = 'high' (notably smoother)

enter image description here

It's working in this online Stackblitz, but for some reason NOT working in our own application. Meaning, even after the bicubic results are written back to ctx0 canvas context - the image is NOT smoothed at all. It remains pixelated. The question is why?

https://stackblitz.com/edit/angular-ivy-bga9dz?file=src/app/app.component.ts

UPDATE: the smoothing algorithm does appear to be applied to our canvas, however it appears to reposition the imageData each time with respect to the upper left hand corner. i.e. After applying our zoom function, we call drawImage() at those coordinates, then run the imageData it thru the smoothing algorithm, then drawImage() again. The smoothed image area is no longer where I expected it.

0

There are 0 answers