2017-05-04 92 views
0

我想用矩陣練習像素操作以從另一個圖像中提取圖像。圖像變換矩陣

這是我的CSS變換矩陣來完成: https://www.noelshack.com/2017-18-1493893008-capture-2.png

與左圖像「L」我的地方周圍的圖像及右眼圖像「R」在4點我找的內容轉型。

爲此我使用css的屬性轉換,但我想手動進行操作。

CSS版本:

matrix3d(1.5456325781948308,1.6561987730956724,0,0.0012239101773909712,-0.4663849104791486,2.218793881308064,0,0.0009095626603861196,0,0,1,0,12.247969030166722,-17.754955132517754,0,0.9951722722714726) 

矩陣 'M':

[[1.5456325781948308, 1.6561987730956724, 0, 0.0012239101773909712], 
[-0.4663849104791486, 2.218793881308064, 0, 0.0009095626603861196], 
[0, 0, 1, 0], 
[12.247969030166722, -17.754955132517754, 0, 0.9951722722714726]] 

我想知道在圖像R什麼是他們的像素相關圖像中的位置L.

每個像素

例如R中的(0,0)是(52,203)中的R. 對於這個我做了這個計算。

M * P = P' 

P是在R圖像 P上的像素位置」是在L圖像的像素位置

P矩陣被定義這樣的:

[[x], 
[y], 
[0], 
[1]] 

所以對於0,0位置,我這樣做:

[[1.5456325781948308, 1.6561987730956724, 0, 0.0012239101773909712], 
[-0.4663849104791486, 2.218793881308064, 0, 0.0009095626603861196], 
[0, 0, 1, 0], 
[12.247969030166722, -17.754955132517754, 0, 0.9951722722714726]] 

X 

[[0], 
[0], 
[0], 
[1]] 

= 

[[0.0012239101773909712], 
[0.0009095626603861196], 
[0], 
[0.9951722722714726]] 

這是結果,但2第一個組成部分: (0.0012239101773909712,0.0009095626603861196) 太小於預期值。你能幫我找到問題嗎?

scincerly, MatrixCuriosity。

+0

這個矩陣是直接變換L-> R還是後面一個R-> L?爲什麼矩陣是用於2D轉換的4x4而不是3x3? Shift組件(12/-17?)看起來太小。 – MBo

+0

交叉參考:請參閱https://math.stackexchange.com/a/339033/35416瞭解給定四個點及其圖像的矩陣步驟。答案和評論包括一些正在運行的JavaScript/CSS演示。 – MvG

回答

0

這些是齊次座標。因此給定一些[x1,y1,z1,1]作爲輸入,你可以得到一些[x2,y2,z2,w2],但他們描述的實際位置是[x2/w2,y2/w2,z2/w2]除以最後的座標。

但是,這不會導致您預期的結果。也沒有將矩陣替換爲其附加(或等價的逆),也不是它的轉置。這兩個都是容易出錯的約定,所以在不花太多心思考慮你實際擁有和應該擁有哪個版本的情況下,嘗試所有四種選擇(帶和不帶輔助,帶和不帶轉置)解決了大量的小問題。

但不是你的。所以我下一個最好的選擇是,你期望的座標是從圖像的某個角度測量的,而CSS屬性transform-origin處於它的初始值50% 50% 0,所以座標系的原點實際上在對象的中心。

實際上爲此共享HTML和CSS可能會讓我驗證這個假設。現在你必須檢查這是否適用於你。我記得當我上次創建a projective image transformation demoanswer a question about finding the transform時,我故意設置了transform-origin: 0 0;(以及各種供應商的前綴版本)以避免這些問題。

0

非常感謝MvG。

我按照你的鏈接,我找到了我想要[https://math.stackexchange.com/a/339033] 只有一兩件事,我有反轉C矩陣找到像素相關大號< -R

我分享我的代碼給的想法你所要做的 你可以找到我在功能computeMat()實現

<style> 
body { 
    touch-action: none; 
    overflow-y: hidden; 
} 
#canvas_toeic 
{ 
    position:absolute; 
    top:0; 
    left:0; 
} 
</style> 

<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/mathjs/3.12.2/math.min.js"></script> 

</head> 



<body> 
    <canvas id="canvas_toeic" width="600" height="400"> 
    </canvas> 

<script type="text/javascript"> 

    var image = new Image(); 
    image.src = 'image.jpg'; 
    image.onload = function() { 

     var c = document.getElementById("canvas_toeic"); 
     var ratio = image.width/image.height; 
     var canvasWidth = document.body.clientWidth; 
     var canvasHeight = canvasWidth/ratio; 


     if(document.body.clientHeight < canvasHeight) 
     { 
      canvasHeight = document.body.clientHeight; 
      canvasWidth = canvasHeight * ratio; 
     } 

     var canvasLargeur = canvasWidth; 
     var canvasLongueur = canvasHeight; 

     if(canvasLargeur < canvasHeight) { 
      canvasLargeur = canvasHeight; 
      canvasLongueur = canvasWidth; 
     } 

     var canvasPixelRatio = canvasLargeur/image.width; 

     c.setAttribute("width", canvasWidth); 
     c.setAttribute("height", canvasHeight); 

     var ctx = c.getContext("2d"); 
     var idPoint = -1; 

     var points = []; 
     for(var i = 0; i < 4; i++) 
      points[i] = {x:0, y:0}; 

     var marginImage = Math.round(40 * canvasPixelRatio); 

     points[0].x = marginImage; 
     points[0].y = marginImage; 
     points[1].x = marginImage; 
     points[1].y = canvasHeight - marginImage; 
     points[2].x = canvasWidth - marginImage; 
     points[2].y = canvasHeight - marginImage; 
     points[3].x = canvasWidth - marginImage; 
     points[3].y = marginImage; 

     function draw(points) { 
      console.log("draw"); 

      // Fond 
      ctx.fillStyle = "#222"; 
      ctx.fillRect(0, 0, canvasWidth, canvasHeight); 

      ctx.drawImage(image, marginImage, marginImage, canvasWidth - marginImage * 2, canvasHeight - marginImage * 2); // this fait référence à l'objet courant (=image) 

      if(idPoint == -1) 
       ctx.lineWidth = 3 * canvasPixelRatio; 
      else 
       ctx.lineWidth = 5 * canvasPixelRatio; 

      ctx.beginPath();  // Début du chemin 
      ctx.lineJoin = "round"; 
      ctx.lineCap = "round"; 
      ctx.strokeStyle = "rgba(64, 128, 255, 0.5)"; 
      ctx.moveTo(points[0].x, points[0].y); // Le tracé part du point 50,50 
      for(var i = 0; i < 4; i++) 
       ctx.lineTo(points[i].x, points[i].y); // Un segment est ajouté vers 200,200 
      ctx.closePath();  // Fermeture du chemin (facultative) 
      ctx.stroke(); 


      for(var i = 0; i < 4; i++) 
      { 
       var radius = 30 * canvasPixelRatio; 

       if(idPoint == i) 
        radius = 60 * canvasPixelRatio; 

       ctx.beginPath(); 
       ctx.arc(points[i].x, points[i].y, radius, 0, Math.PI*2, true); 
       ctx.strokeStyle = "#FF8800"; 
       ctx.fillStyle = "rgba(255, 128, 0, 0.5)"; 
       ctx.fill(); 
       ctx.stroke(); 
      } 

      if(idPoint != -1) 
      { 
       var zoomWidth = canvasWidth/3; 
       var zoomHeight = canvasHeight/3; 
       var zoomMargin = 5; 
       var zoomAroundWidth = 50; 
       var zoomAroundHeight = zoomAroundWidth/ratio; 

       var positionMouse = points[idPoint]; 
       var imagePositionX = (positionMouse.x - marginImage)/(canvasWidth - marginImage * 2) * image.width; 
       var imagePositionY = (positionMouse.y - marginImage)/(canvasHeight - marginImage * 2) * image.height; 

       var zoomX = 0; 
       var zoomY = 0; 

       if(imagePositionX < image.width/2) 
        zoomX = canvasWidth - zoomWidth; 
       if(imagePositionY < image.height/2) 
        zoomY = canvasHeight - zoomHeight; 

       ctx.fillStyle = "#F08"; 
       ctx.fillRect(zoomX, zoomY, zoomWidth, zoomHeight); 
       ctx.drawImage(image, imagePositionX - zoomAroundWidth, imagePositionY - zoomAroundHeight, zoomAroundWidth * 2, zoomAroundHeight * 2, zoomX + zoomMargin, zoomY + zoomMargin, zoomWidth - zoomMargin * 2, zoomHeight - zoomMargin * 2); 

       ctx.lineWidth = 3 * canvasPixelRatio; 

       ctx.beginPath();  
       ctx.lineJoin = "round"; 
       ctx.lineCap = "round"; 
       ctx.strokeStyle = "rgba(255, 0, 0, 0.5)"; 
       ctx.moveTo(zoomX, zoomY + zoomHeight/2);  
       ctx.lineTo(zoomX + zoomWidth, zoomY + zoomHeight/2); 
       ctx.moveTo(zoomX + zoomWidth/2, zoomY);  
       ctx.lineTo(zoomX + zoomWidth/2, zoomY + zoomHeight); 
       ctx.closePath(); 
       ctx.stroke(); 
      } 
     } 

     function nearPoint(points, x, y) 
     { 
      var radiusDetection = 60 * canvasPixelRatio; 
      var distances = []; 

      for(i = 0; i < 4; i++) { 
       var mx = x - points[i].x; 
       var my = y - points[i].y; 
       distances[i] = Math.sqrt(mx * mx + my * my); 
      } 

      minI = 0; 
      minD = distances[0]; 

      for(i = 1; i < 4; i++) 
      { 
       if(minD > distances[i]) 
       { 
        minD = distances[i]; 
        minI = i; 
       } 
      } 

      if(minD <= radiusDetection) 
       return minI; 

      return -1; 
     } 

     function getTouchPosition(e) 
     { 
      var target = null; 
      var mouse = null; 

      if(e.changedTouches != undefined) 
      { 
       var touches = e.changedTouches; 
       mouse = touches[0]; 
       target = touches[0].target; 
      } 
      else if(e.originalTarget != undefined) 
      { 
       mouse = e; 
       target = e.originalTarget; 
      } 

      var coordX = 0; 
      var coordY = 0; 

      if(mouse.layerX != undefined) 
      { 
       coordX = mouse.layerX; 
       coordY = mouse.layerY; 
      } 
      else 
      { 
       coordX = mouse.pageX; 
       coordY = mouse.pageY; 
      } 

      var x = coordX - target.offsetLeft; 
      var y = coordY - target.offsetTop; 

      if(x < 0) x = 0; 
      if(y < 0) y = 0; 
      if(x >= canvasWidth) x = canvasWidth - 1; 
      if(y >= canvasHeight) y = canvasHeight - 1; 

      return {'x':x, 'y':y}; 
     } 

     function mouseDown(e) 
     { 
      var position = getTouchPosition(e); 

      idPoint = nearPoint(points, position.x, position.y); 

      if(idPoint == -1) 
      { 
       if(position.x < marginImage * 3 && position.y < marginImage * 3) 
       { 
        computeMat(); 
       } 
      } 
     } 

     function mouseUp(e) 
     { 
      if(idPoint != -1) 
      { 
       idPoint = -1; 
       draw(points); 
      } 
     } 

     function mouseMove(e) 
     { 
      if(idPoint != -1) 
      { 
       var position = getTouchPosition(e); 
       points[idPoint].x = position.x; 
       points[idPoint].y = position.y; 
       draw(points); 
      } 
     } 

     function cancelDefault(e) 
     { 
      e.preventDefault(); 
     } 

     function matStep12(pts) 
     { 
      var matP = [ 
       [pts[0].x, pts[1].x, pts[2].x], 
       [pts[0].y, pts[1].y, pts[2].y], 
       [1, 1, 1] 
       ]; 

      var vecP = [[pts[3].x], [pts[3].y], [1]]; 

      var matPi = math.inv(matP); 
      var vecPi = math.multiply(matPi, vecP); 

      var result = [ 
        [pts[0].x * vecPi[0][0], pts[1].x * vecPi[1][0], pts[2].x * vecPi[2][0]], 
        [pts[0].y * vecPi[0][0], pts[1].y * vecPi[1][0], pts[2].y * vecPi[2][0]], 
        [vecPi[0][0], vecPi[1][0], vecPi[2][0]] 
       ]; 

      return result; 
     } 

     function distance(a, b) 
     { 
      var mx = b.x - a.x; 
      var my = b.y - a.y; 

      return Math.sqrt(mx * mx + my * my); 
     } 

     function computeMat() 
     { 
      var pts = getPointRelativePosition(); 

      var widthT = distance(pts[0], pts[3]); 
      var widthB = distance(pts[1], pts[2]); 
      var heightL = distance(pts[0], pts[1]); 
      var heightR = distance(pts[2], pts[3]); 

      var maxWidth = (widthT > widthB) ? widthT : widthB; 
      var maxHeight = (heightL > heightR) ? heightL : heightR; 
      var imgWidth = Math.round(maxWidth); 
      var imgHeight = Math.round(maxHeight); 


      var matA = matStep12(pts); 
      var matB = matStep12([{x:0,y:0}, {x:0,y:maxHeight}, {x:maxWidth,y:maxHeight}, {x:maxWidth,y:0}]); 
      var matC = math.multiply(matB, math.inv(matA)); 
      var matCi = math.inv(matC); 

      console.log('width:' + imgWidth + ', height:' + imgHeight); 
      printMat(matC); 


      // construct image with transformation matrice 

      imageData = ctx.createImageData(imgWidth, imgHeight); 

      var tempCanvas = document.createElement('canvas'); 
      var tempCtx = tempCanvas.getContext('2d'); 
      tempCanvas.width = image.width; 
      tempCanvas.height = image.height; 
      tempCtx.drawImage(image, 0, 0, image.width, image.height); 
      var imageDataSrc = tempCtx.getImageData(0, 0, image.width, image.height); 

      var mz = [matCi[0][2], matCi[1][2], matCi[2][2]]; 

      for(var y = 0; y < imgHeight; y++) 
      { 
       var my = [matCi[0][1] * y, matCi[1][1] * y, matCi[2][1] * y]; 

       var offsetY = y * imgWidth; 
       for(var x = 0; x < imgWidth; x++) 
       { 
        var mx = [matCi[0][0] * x, matCi[1][0] * x, matCi[2][0] * x]; 

        var cx = mx[0] + my[0] + mz[0]; 
        var cy = mx[1] + my[1] + mz[1]; 
        var cz = mx[2] + my[2] + mz[2]; 

        var px = Math.round(cx/cz); 
        var py = Math.round(cy/cz); 

        if(px < 0.0 || py < 0.0 || px >= image.width || py >= image.height) 
        { 
         imageData.data[pixelIndex] = 0; 
         imageData.data[pixelIndex + 1] = 255; 
         imageData.data[pixelIndex + 2] = 0; 
         imageData.data[pixelIndex + 3] = 255; 
        } 
        else 
        { 
         var pixelIndex = (offsetY + x) * 4; 
         var pixelIndexSrc = (py * image.width + px) * 4; 

         imageData.data[pixelIndex] = imageDataSrc.data[pixelIndexSrc]; 
         imageData.data[pixelIndex + 1] = imageDataSrc.data[pixelIndexSrc + 1]; 
         imageData.data[pixelIndex + 2] = imageDataSrc.data[pixelIndexSrc + 2]; 
         imageData.data[pixelIndex + 3] = 255; 
        } 
       } 
      } 



      // here to do, image analysis 

     } 

     function getPointRelativePosition() 
     { 
      var pointOrigin = []; 

      for(i = 0; i < 4; i++) 
      { 
       pointOrigin[i] = {x:(points[i].x - marginImage) * image.width/(canvasWidth - marginImage * 2), y:(points[i].y - marginImage) * image.height/(canvasHeight - marginImage * 2)}; 
      } 

      return pointOrigin; 
     } 

     function getPointPosition() 
     { 
      var pointOrigin = []; 

      for(i = 0; i < 4; i++) 
      { 
       pointOrigin[i] = {x:(points[i].x - marginImage)/(canvasWidth - marginImage * 2), y:(points[i].y - marginImage)/(canvasHeight - marginImage * 2)}; 
      } 

      return pointOrigin; 
     } 

     function printPoint(pts) 
     { 
      var result = ''; 


      for(var i = 0; i < 4; i++) 
      { 
       result += "{x:" + pts[i].x + ", y:" + pts[i].y + "},\n"; 
      } 

      console.log(result); 
     } 

     function printMat(mat) 
     { 
      var result = ''; 

      for(var i = 0; i < mat.length; i++) 
      { 
       result += "["; 

       for(var j = 0; j < mat[i].length; j++) 
       { 
        result += mat[i][j] + ", "; 
       } 

       result += "],\n"; 
      } 

      console.log(result); 
     } 

     function canvasResize() 
     { 
      if(canvasWidth != document.body.clientWidth && canvasHeight != document.body.clientHeight) 
      { 
       var transformPoint = getPointPosition(); 

       ratio = image.width/image.height; 
       canvasWidth = document.body.clientWidth; 
       canvasHeight = canvasWidth/ratio; 


       if(document.body.clientHeight < canvasHeight) 
       { 
        canvasHeight = document.body.clientHeight; 
        canvasWidth = canvasHeight * ratio; 
       } 

       canvasLargeur = canvasWidth; 
       canvasLongueur = canvasHeight; 

       if(canvasLargeur < canvasHeight) { 
        canvasLargeur = canvasHeight; 
        canvasLongueur = canvasWidth; 
       } 

       canvasPixelRatio = canvasLargeur/image.width; 

       c.setAttribute("width", canvasWidth); 
       c.setAttribute("height", canvasHeight); 

       marginImage = Math.round(40 * canvasPixelRatio); 

       for(i = 0; i < 4; i++) 
       { 
        points[i].x = transformPoint[i].x * (canvasWidth - marginImage * 2) + marginImage; 
        points[i].y = transformPoint[i].y * (canvasHeight - marginImage * 2) + marginImage; 
       } 

       draw(points); 
      } 
     } 

     c.addEventListener("mousedown", mouseDown, false); 
     c.addEventListener("mouseup", mouseUp, false); 
     c.addEventListener("mousemove", mouseMove, false); 

     c.addEventListener("touchstart", mouseDown, false); 
     c.addEventListener("touchend", mouseUp, false); 
     c.addEventListener("touchmove", mouseMove, false); 

     document.addEventListener("touchstart", cancelDefault, true); 
     document.addEventListener("touchend", cancelDefault, true); 
     document.addEventListener("touchmove", cancelDefault, true); 

     setInterval(canvasResize, 30); 

     draw(points); 

    }; 



</script>