簡體   English   中英

WebGL glfx.js矩陣變換(透視)在旋轉時裁剪圖像

[英]WebGL glfx.js matrix transform (perspective) crops the image if it rotates

我正在使用glfx.js庫,以便使用矩陣轉換為圖像創建透視效果。 在我的應用程序中,該系統的工作方式類似於photoshop的智能對象(在其中渲染平面圖像並在渲染后獲得透視結果)

glfx.js使用此功能canvas.perspective(before, after)通過在圖像中的4個點進行協調之前和之后進行分配,將矩陣變換應用於圖像,並且它在后台運行Matrix命令以變換圖像。

我的問題是,如果將轉換后應用於圖像的結果圖像大於原始圖像(如果旋轉圖像,則可能發生),則WebGL畫布將裁剪我的圖像。

看下面的小提琴:

https://jsfiddle.net/human_a/o4yrheeq/

 window.onload = function() { try { var canvas = fx.canvas(); } catch (e) { alert(e); return; } // convert the image to a texture var image = document.getElementById('image'); var texture = canvas.texture(image); // apply the perspective filter canvas.draw(texture).perspective( [0,0,774,0,0,1094,774,1094], [0,389,537,0,732,1034,1269,557] ).update(); image.src = canvas.toDataURL('image/png'); // or even if you replace the image with the canvas // image.parentNode.insertBefore(canvas, image); // image.parentNode.removeChild(image); }; 
 <script src="https://evanw.github.io/glfx.js/glfx.js"></script> <img id="image" crossOrigin="anonymous" src="https://images.unsplash.com/photo-1485207801406-48c5ac7286b2?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=600&fit=max&s=9bb1a18da78ab0980d5e7870a236af88"> 

關於如何使WebGL畫布適合旋轉的圖像(而不是使圖像變小)或以某種方式提取整個圖像而不是裁剪的圖像的任何想法?

更多像素

沒有涵蓋所有解決方案的解決方案。 這是因為當您從2D轉換為3D時,投影圖像的大小可能會接近無限大(近限幅可防止無限遠),因此無論您將圖像輸出多大,總有可能會應用某些限幅。

避免了這種警告,在大多數情況下都可以找到一種避免裁剪的解決方案。 這非常簡單,只需擴展畫布即可容納其他內容。

找到界限

為了簡化計算,我將after數組更改為一組標准化點(它們將after坐標表示為圖像尺寸的比例因子)。 然后,我使用圖像大小轉換為真實像素坐標。 然后從中開始鍛煉紋理的最小尺寸,以同時保留原始圖像和投影。

有了這些信息,我就可以創建紋理(作為畫布)來繪制圖像。 必要時調整befor數組(以防某些投影點位於負空間中)並應用濾鏡。

因此,我們有一個具有寬度和高度的圖像對象。 您已經掌握了這些觀點。

// assuming image has been loaded and is ready
var imgW = image.naturalWidth;
var imgH = image.naturalHeight;

設置轉角數組(之前)

var before = [0, 0, imgW, 0, 0, imgH, imgW, imgH];

投影點。 為了更容易處理,我將投影點歸一化為圖像大小

var projectNorm =  [[0, 0.3556], [0.6938, 0], [0.9457, 0.9452], [1.6395, 0.5091]];

如果要使用小提琴的after數組中的絕對坐標,請使用以下代碼。 下一步之后,該片段中的標准化將被反轉,因此您可以跳過標准化。 由於時間緊迫,我很快就更新了答案。

var afterArray = [0,389,537,0,732,1034,1269,557];
projectNorm = [];
for(var i = 0; i < afterArray.length; i+= 2){
     afterArray.push([afterArray[i] / before[i], afterArray[i + 1] / before[i + 1]]);
}

現在計算投影的大小。 這是重要的部分,因為它可以計算出畫布的大小。

var top, left, right, bottom;
top = 0;
left = 0;
bottom = imgH;
right = imgW;
var project = projectNorm.map(p => [p[0] * imgW, p[1] * imgH]);
project.forEach(p => {
    top = Math.min(p[1], top);
    left = Math.min(p[0], left);
    bottom = Math.max(p[1], bottom);
    right = Math.max(p[0], right);
});

現在我們已經收集了所有需要的數據,我們可以創建一個可以容納投影的新圖像。 (假設投影點真實於投影)

var texture = document.createElement("canvas");
var ctx = texture.getContext("2d");
texture.width = Math.ceil(right - left);
texture.height = Math.ceil(bottom - top);

在0,0處繪制圖像

ctx.setTransform(1, 0, 0, 1, left, top); // put origin so image is at 0,0
ctx.drawImage(image,0,0);
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform

然后展平投影點數組

var after = [];
project.forEach(p => after.push(...p));

將所有點移到正投影空間

after.forEach((p,i) => {
    if (i % 2) {
        before[i] += -top;
        after[i] += -top;
    } else {
        before[i] += -left;
        after[i] += -left;
    }
});

最后一步是創建glfx.js對象並應用過濾器

// create a fx canvas
var canvas = fx.canvas();
// create the texture 
var glfxTexture = canvas.texture(texture);
// apply the filter
canvas.draw(glfxTexture).perspective( before, after ).update();
// show the result on the page
document.body.appendChild(canvas);

演示

使用上述方法的代碼段演示(圖像加載的輕微修改)

 // To save time typing I have just kludged a simple load image wait poll waitForLoaded(); function waitForLoaded(){ if(image.complete){ projectImage(image); }else{ setTimeout(waitForLoaded,500); } } function projectImage(image){ var imgW = image.naturalWidth; var imgH = image.naturalHeight; var projectNorm = [[0, 0.3556], [0.6938, 0], [0.9457, 0.9452], [1.6395, 0.5091]]; var before = [0, 0, imgW, 0, 0, imgH, imgW, imgH]; var top, left, right, bottom; top = 0; left = 0; bottom = imgH; right = imgW; var project = projectNorm.map(p => [p[0] * imgW, p[1] * imgH]); project.forEach(p => { top = Math.min(p[1], top); left = Math.min(p[0], left); bottom = Math.max(p[1], bottom); right = Math.max(p[0], right); }); var texture = document.createElement("canvas"); var ctx = texture.getContext("2d"); texture.width = Math.ceil(right - left); texture.height = Math.ceil(bottom - top); ctx.setTransform(1, 0, 0, 1, left, top); // put origin so image is at 0,0 ctx.drawImage(image,0,0); ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform var after = []; project.forEach(p => after.push(...p)); after.forEach((p,i) => { if (i % 2) { before[i] += -top; after[i] += -top; } else { before[i] += -left; after[i] += -left; } }); // create a fx canvas var canvas = fx.canvas(); // create the texture var glfxTexture = canvas.texture(texture); // apply the filter canvas.draw(glfxTexture).perspective( before, after ).update(); // show the result on the page document.body.appendChild(canvas); } 
 #image { display : none; } 
 <script src="https://evanw.github.io/glfx.js/glfx.js"></script> <img id="image" crossOrigin="anonymous" src="https://images.unsplash.com/photo-1485207801406-48c5ac7286b2?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&s=9bb1a18da78ab0980d5e7870a236af88"> 

注意事項和警告

請注意 ,投影點(陣列之后)並不總是與投影圖像的最終角點匹配。 如果發生這種情況,則最終的圖像可能會被剪切。

注意僅當之前的點代表原始圖像的末端時,此方法才有效。 如果這些點(之前)在圖像內,則此方法可能會失敗。

警告不會審核生成的圖像尺寸。 大圖像會導致瀏覽器變慢,有時會崩潰。 對於生產代碼,應盡最大努力使圖像大小保持在使用代碼的設備的限制內。 客戶很少返回緩慢和/或崩潰的頁面。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM