2015-02-23 39 views
1

我的項目有問題。解決。畫布上質量最差的視角圖像

我正在爲設計師開發一個透視樣機創建模塊。用戶上傳圖片,並通過製作一些透視圖計算讓他們在模型中放置。然後用戶可以下載這個圖像。我用js在客戶端做了所有這些。

但是,在像這樣的透視計算畫布上繪製的圖像存在問題;

樣品IMG:http://oi62.tinypic.com/2h49dec.jpg

原單圖像尺寸:6500 X 3592,你可以看到在圖像邊緣蔓延...

我嘗試了一些工藝類似ctx.imageSmoothingEnabled真等。但結果是總是一樣的。

我能做些什麼來解決這個問題?你怎麼看待這件事?

編輯

有關更多細節;

我從用戶那裏得到一個圖像(無分辨率),然後裁剪它以獲得樣機比例。例如,在我的示例圖像中,用戶圖像被裁剪爲16:9的imac比率,然後使用四個點的屏幕進行計算。順便說一句,我的樣機圖像尺寸是6500 x 3592.所以我製作了縮放,轉換等裁剪後的圖像,並將其放置在畫布上的樣機上。然後使用blob將此映像下載到客戶端...

謝謝。

+0

如果你放大圖像,你經常會得到像素化。以更大的像素密度和放大的圖像進行攝像通常不會顯示出儘可能多的像素化。 – markE 2015-02-23 23:32:43

回答

0

問題是(最有可能,但沒有代碼顯示如此..)圖像實際上太大了。

畫布通常使用雙線性插值(2×2採樣)而不是雙立方(4×4採樣)。這意味着,如果您在一個區塊中將比例縮小很多,算法會跳過一些本應採樣的像素,從而產生更像素化的外觀。

解決方案的辦法是逐步調整圖像大小,即。本身的50%可以重複,直到達到合適的尺寸。然後使用透視計算。確切的目的地尺寸是您需要通過反覆試驗才能找到的,但一個好的起點是使用最終透視圖像的最大一面。

Here is one way到降壓重新縮放步驟的圖像。

+0

坦率地說,我很困惑:-z我看着@ OgzhnOzlci的圖像,看到了什麼看起來像是放大圖像的一部分(在縮放框中),我認爲這個問題是關於放大。但如果問題是減少6500 x 3592圖像,那麼你有一個很好的答案和一個很好的問題的「線條之間的閱讀」。:-) – markE 2015-02-24 04:10:19

+0

@markE我認爲這是原始圖像的輸入圖像,但您可能是正確的,它可能是示例圖像的原始大小,並且不會聲明輸出大小。 OP應該澄清。 – K3N 2015-02-24 07:31:58

1

已解決。

我在畫布上使用perspective.js進行計算。所以我對這個js源碼做了一些修改。

如果你想使用或檢查來源;

// Copyright 2010 futomi http://www.html5.jp/ 
// 
// Licensed under the Apache License, Version 2.0 (the "License"); 
// you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at 
// 
// http://www.apache.org/licenses/LICENSE-2.0 

// perspective.js v0.0.2 
// 2010-08-28 
/* ------------------------------------------------------------------- 
* define objects (name space) for this library. 
* ----------------------------------------------------------------- */ 
if (typeof html5jp == 'undefined') { 
    html5jp = new Object(); 
} 

(function() { 


html5jp.perspective = function(ctxd, image) { 
    // check the arguments 
    if (!ctxd || !ctxd.strokeStyle) { 
     return; 
    } 
    if (!image || !image.width || !image.height) { 
     return; 
    } 
    // prepare a <canvas> for the image 
    var cvso = document.createElement('canvas'); 
    cvso.width = parseInt(image.width) * 2; 
    cvso.height = parseInt(image.height) * 2; 
    var ctxo = cvso.getContext('2d'); 
    ctxo.drawImage(image, 0, 0, cvso.width, cvso.height); 
    // prepare a <canvas> for the transformed image 
    var cvst = document.createElement('canvas'); 
    cvst.width = ctxd.canvas.width; 
    cvst.height = ctxd.canvas.height; 
    var ctxt = cvst.getContext('2d'); 

    ctxt.imageSmoothingEnabled = true; 
    ctxt.mozImageSmoothingEnabled = true; 
    ctxt.webkitImageSmoothingEnabled = true; 
    ctxt.msImageSmoothingEnabled = true; 


    // parameters 
    this.p = { 
     ctxd: ctxd, 
     cvso: cvso, 
     ctxo: ctxo, 
     ctxt: ctxt 
    } 
}; 

var proto = html5jp.perspective.prototype; 

proto.draw = function(points) { 
    var d0x = points[0][0]; 
    var d0y = points[0][1]; 
    var d1x = points[1][0]; 
    var d1y = points[1][1]; 
    var d2x = points[2][0]; 
    var d2y = points[2][1]; 
    var d3x = points[3][0]; 
    var d3y = points[3][1]; 
    // compute the dimension of each side 
    var dims = [ 
     Math.sqrt(Math.pow(d0x - d1x, 2) + Math.pow(d0y - d1y, 2)), // top side 
     Math.sqrt(Math.pow(d1x - d2x, 2) + Math.pow(d1y - d2y, 2)), // right side 
     Math.sqrt(Math.pow(d2x - d3x, 2) + Math.pow(d2y - d3y, 2)), // bottom side 
     Math.sqrt(Math.pow(d3x - d0x, 2) + Math.pow(d3y - d0y, 2)) // left side 
    ]; 
    // 
    var ow = this.p.cvso.width; 
    var oh = this.p.cvso.height; 
    // specify the index of which dimension is longest 
    var base_index = 0; 
    var max_scale_rate = 0; 
    var zero_num = 0; 
    for (var i = 0; i < 4; i++) { 
     var rate = 0; 
     if (i % 2) { 
      rate = dims[i]/ow; 
     } else { 
      rate = dims[i]/oh; 
     } 
     if (rate > max_scale_rate) { 
      base_index = i; 
      max_scale_rate = rate; 
     } 
     if (dims[i] == 0) { 
      zero_num++; 
     } 
    } 
    if (zero_num > 1) { 
     return; 
    } 
    // 
    var step = 0.10; 
    var cover_step = step * 250; 
    // 
    var ctxo = this.p.ctxo; 
    var ctxt = this.p.ctxt; 
    //*** ctxt.clearRect(0, 0, ctxt.canvas.width, ctxt.canvas.height); 
    if (base_index % 2 == 0) { // top or bottom side 
     var ctxl = this.create_canvas_context(ow, cover_step); 
     var cvsl = ctxl.canvas; 
     for (var y = 0; y < oh; y += step) { 
      var r = y/oh; 
      var sx = d0x + (d3x - d0x) * r; 
      var sy = d0y + (d3y - d0y) * r; 
      var ex = d1x + (d2x - d1x) * r; 
      var ey = d1y + (d2y - d1y) * r; 
      var ag = Math.atan((ey - sy)/(ex - sx)); 
      var sc = Math.sqrt(Math.pow(ex - sx, 2) + Math.pow(ey - sy, 2))/ow; 
      ctxl.setTransform(1, 0, 0, 1, 0, -y); 
      ctxl.drawImage(ctxo.canvas, 0, 0); 
      // 
      ctxt.translate(sx, sy); 
      ctxt.rotate(ag); 
      ctxt.scale(sc, sc); 
      ctxt.drawImage(cvsl, 0, 0); 
      // 
      ctxt.setTransform(1, 0, 0, 1, 0, 0); 
     } 
    } else if (base_index % 2 == 1) { // right or left side 
     var ctxl = this.create_canvas_context(cover_step, oh); 
     var cvsl = ctxl.canvas; 
     for (var x = 0; x < ow; x += step) { 
      var r = x/ow; 
      var sx = d0x + (d1x - d0x) * r; 
      var sy = d0y + (d1y - d0y) * r; 
      var ex = d3x + (d2x - d3x) * r; 
      var ey = d3y + (d2y - d3y) * r; 
      var ag = Math.atan((sx - ex)/(ey - sy)); 
      var sc = Math.sqrt(Math.pow(ex - sx, 2) + Math.pow(ey - sy, 2))/oh; 
      ctxl.setTransform(1, 0, 0, 1, -x, 0); 
      ctxl.drawImage(ctxo.canvas, 0, 0); 
      // 
      ctxt.translate(sx, sy); 
      ctxt.rotate(ag); 
      ctxt.scale(sc, sc); 
      ctxt.drawImage(cvsl, 0, 0); 
      // 
      ctxt.setTransform(1, 0, 0, 1, 0, 0); 
     } 
    } 
    // set a clipping path and draw the transformed image on the destination canvas. 
    this.p.ctxd.save(); 
    this.set_clipping_path(this.p.ctxd, [ 
     [d0x, d0y], 
     [d1x, d1y], 
     [d2x, d2y], 
     [d3x, d3y] 
    ]); 
    this.p.ctxd.drawImage(ctxt.canvas, 0, 0); 
    this.p.ctxd.restore(); 
} 



proto.create_canvas_context = function(w, h) { 
    var canvas = document.createElement('canvas'); 
    canvas.width = w; 
    canvas.height = h; 
    var ctx = canvas.getContext('2d'); 

    ctx.imageSmoothingEnabled = true; 
    ctx.mozImageSmoothingEnabled = true; 
    ctx.webkitImageSmoothingEnabled = true; 
    ctx.msImageSmoothingEnabled = true; 


    return ctx; 
}; 

proto.set_clipping_path = function(ctx, points) { 
    ctx.beginPath(); 
    ctx.moveTo(points[0][0], points[0][1]); 
    for (var i = 1; i < points.length; i++) { 
     ctx.lineTo(points[i][0], points[i][1]); 
    } 
    ctx.closePath(); 
    ctx.clip(); 
}; 

})();