javascript - 使用最近邻算法缩放 Canvas 图像

标签 javascript algorithm image-processing canvas scaling

我正在使用最近邻算法在 Canvas 上缩放图像。但是,当我将比例尺移得更高时,图像有白线创建一个方形阵列

原始图像

enter image description here

在我移动比例尺之后

enter image description here

缩放有效,但问题仅在于白线。 对于源代码,我将在底部提供

1.html

 <!DOCTYPE HTML>
 <html>
 <head>
 <title>Prototype PC</title>
 </head>
 <body>
 <canvas id='canvas1'></canvas>
 <hr>
 <button id='read'>READ IMAGE</button>
 <hr>
      Scale <input type='range' value='1' min='1' max='5' step='0.25' id='scale'>
      <br><button id='default2'>Default Scalling</button>
 <hr/>
 </body>
 <style>
 body{
      background : rgba(255,255,255,1);
 }
 </style>
 <script src='imagine.js'></script>
 <script>

 var canvas = document.getElementById('canvas1')
 var obj = new pc(canvas)
 obj.image2canvas("565043_553561101348179_1714194038_a.jpg")

 var tes = new Array()
 document.getElementById('read').addEventListener('click',function(){
    tes = obj.image2read()
 })

 document.getElementById('scale').addEventListener('change',function(){
    var scaleval = this.value
    var xpos = 0
    var ypos = 0
    var xnow = 0
    var ynow = 0
    var objW = obj.width
    var objH = obj.height

    tesbackup = new Array()
    for(var c=0; c<tes.length; c++){
        temp = new Array()
        for(var d=0; d<4; d++){
            temp.push(255)
        }
        tesbackup.push(temp)
    }
    //end of copy
    for(var i=0; i<tes.length; i++){
        xpos = obj.i2x(i)
        ypos = obj.i2y(i)
        xnow = Math.round(xpos) * scaleval)
        ynow = Math.round(ypos) * scaleval)
        if (xnow < objW && ynow < objH) {
            for (var j=0; j<scaleval; j++) {
                for (var k=0; k<scaleval; k++) {
                    var idxnow = obj.xy2i(xnow,ynow)
                    tesbackup[idxnow][0] = tes[i][0]
                    tesbackup[idxnow][1] = tes[i][1]
                    tesbackup[idxnow][2] = tes[i][2]
                }
              }
           }
        }
        obj.array2canvas(tesbackup)
    })
</script>

并且,对于 imagine.js

    function info(text){
        console.info(text)
    }

    function pc(canvas){
        this.canvas = canvas
        this.context = this.canvas.getContext('2d')
        this.width = 0
        this.height = 0
        this.imgsrc = ""
        this.image2read = function(){
            this.originalLakeImageData = this.context.getImageData(0,0, this.width, this.height)
            this.resultArr = new Array()
            this.tempArr = new Array()
            this.tempCount = 0
            for(var i=0; i<this.originalLakeImageData.data.length; i++){
                this.tempCount++
                this.tempArr.push(this.originalLakeImageData.data[i])
                if(this.tempCount == 4){
                    this.resultArr.push(this.tempArr)
                    this.tempArr = []
                    this.tempCount = 0
                }
            }
            info('image2read Success ('+this.imgsrc+') : '+this.width+'x'+this.height)
            return this.resultArr
        }

        this.image2canvas = function(imgsrc){
            var imageObj = new Image()
            var parent = this
            imageObj.onload = function() {
                parent.canvas.width = imageObj.width
                parent.canvas.height = imageObj.height
                parent.context.drawImage(imageObj, 0, 0)
                parent.width = imageObj.width
                parent.height = imageObj.height
                info('image2canvas Success ('+imgsrc+')')
            }   
            imageObj.src = imgsrc
            this.imgsrc = imgsrc
        }

        this.array2canvas = function(arr){
            this.imageData = this.context.getImageData(0,0, this.width, this.height)
            if(this.imageData.data.length != arr.length*4) {
                return false
            }
            for(var i = 0; i < arr.length; i++){
                this.imageData.data[(i*4)] = arr[i][0]
                this.imageData.data[(i*4)+1] = arr[i][1]
                this.imageData.data[(i*4)+2] = arr[i][2]
                this.imageData.data[(i*4)+3] = arr[i][3]
            }
            this.context.clearRect(0, 0, this.width, this.height)
            this.context.putImageData(this.imageData, 0, 0)
            info('Array2Canvas Success ('+this.imgsrc+')')
        }

        this.i2x = function(i){
            return (i % this.width)
        }

        this.i2y = function(i){
            return ((i - (i % this.width))/ this.width)
        }

        this.xy2i = function(x,y){
            return (y * this.width) + (x)
        }

    }

在此先感谢您解决此问题

最佳答案

舍入像素

最近的像素会导致一些缩放像素比其他像素大

是scaleval的值有问题。它有一个 0.25 的步长,当你计算你使用的每个缩放像素地址时(我猜你的代码有语法错误)Math.round(xpos * scaleval) 但是你使用绘制像素只有分数大小,例如 2.75,而不是整数大小,例如 3.0

每个像素的大小 var xSize = Math.round((xpos + 1) * scaleval)-Math.round(xpos * scaleval) 对于 y 相同。这样,当像素缩放不是整数值时,每隔这么多缩放像素将更宽和更高一个像素。

以下是对您的代码的修复,但由于您有许多语法错误和错误,我不得不猜测您的一些意图。

xpos = obj.i2x(i)
ypos = obj.i2y(i)
xnow = Math.round(xpos * scaleval)
ynow = Math.round(ypos * scaleval)
// pixel width and height
var pw = Math.round((xpos + 1) * scaleval) - xnow;
var ph = Math.round((ypos + 1) * scaleval) - ynow;
if (xnow < objW && ynow < objH) {
    for (var y = 0; y < ph; y++) {
        for (var x  =0; x < pw; x++) {
            var idxnow = obj.xy2i(xnow + x, ynow + y)
            tesbackup[idxnow][0] = tes[i][0]
            tesbackup[idxnow][1] = tes[i][1]
            tesbackup[idxnow][2] = tes[i][2]
        }
      }
   }
}

但你并不是真的在做最近邻算法。为此,您迭代每个目标像素以找到最近的像素并使用其颜色。这使您可以轻松地对缩放应用变换,但仍会获取每个像素,而不会由于舍入误差而跳过像素。

最近邻

对缩放旋转和平移图像使用最近邻查找的示例

var scaleFac = 2.3; // scale 1> zoom in 
var panX = 10;  // scaled image pan
var panY = 10; 
var ang = 1;
var w = ctx.canvas.width;  // source image
var h = ctx.canvas.height;
var wd = ctx1.canvas.width;  // destination image
var hd = ctx1.canvas.height;
// use 32bit ints as we are not interested in the channels
var src = ctx.getImageData(0, 0, w, h);
var data = new Uint32Array(src.data.buffer);// source
var dest = ctx1.createImageData(wd, hd);
var zoomData = new Uint32Array(dest.data.buffer);// destination
var xdx = Math.cos(ang) * scaleFac;  // xAxis vector x
var xdy = Math.sin(ang) * scaleFac;  // xAxis vector y
var ind = 0;
var xx,yy;
for(var y = 0; y < hd; y ++){
    for(var x = 0; x < wd; x ++){
        // transform point
        xx = (x * xdx - y * xdy + panX);
        yy = (x * xdy + y * xdx + panY);
        // is the lookup pixel in bounds
        if(xx >= 0 && xx < w && yy >= 0 && yy < h){                
             // use the nearest pixel to set the new pixel
             zoomData[ind++] = data[(xx | 0) + (yy | 0) * w]; // set the pixel
        }else{
             zoomData[ind++] = 0; // pixels outside bound are transparent
        }
    }
}

ctx1.putImageData(dest, 0, 0); // put the pixels onto the destination canvas


    
    

关于javascript - 使用最近邻算法缩放 Canvas 图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41638616/

相关文章:

image-processing - 如何使用霍夫变换检测精确的预定义形状,例如 "W"?

opencv - 读取图像并保存,增加图像大小

javascript - 如何为 Angular 分页自定义模板赋值?

javascript - 如何在 Javascript 中创建自定义对象数组的数组?

javascript - 使用 jQuery 设置 css 属性

c - 此代码如何为任何给定数字找到 2 的下一个最高幂

javascript - Vuejs2:使用对象作为 Prop 时如何判断 Prop 更新?

python - 为所有节点创建具有相同入度和出度的矩阵

algorithm - 使用 golang 在图中查找 Cliques

python-3.x - 力矩保持阈值 : Trilevel Case