2017-05-04 1 views
0

Je souhaite pratiquer la manipulation de pixels avec une matrice pour extraire une image d'une autre.Matrice de transformation d'image

C'est ce que je l'ai fait avec la matrice de transformation css: https://www.noelshack.com/2017-18-1493893008-capture-2.png

Avec l'image de gauche « L » J'ai lieu 4 points autour de l'image et l'image de droite « R » Je trouve le contenu du transformation. Pour cela j'utilise la propriété de transformation du CSS mais je veux faire la manipulation manuellement.

version 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) 

Matrix '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]] 

Je veux savoir pour chaque pixel de l'image R ce sont leur position liée pixel dans l'image L.

Par exemple (0,0) dans R est (52,203) dans R. Pour cela, je fais ce calcul.

M * P = P' 

P est la position de pixel dans l'image R P » est la position de pixel dans l'image de L

matrice P est définie comme:

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

Ainsi, pour la 0,0 poste , Je fais ceci:

[[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]] 

Ceci est le résultat, mais le 2 premier composant: (0,0012239101773909712, 0,0009095626603861196) est trop petit que prévu. pouvez-vous m'aider à trouver le problème?

scincerly, MatrixCuriosity.

+0

Cette matrice est-elle destinée à la transformation directe L-> R ou à l'inverse de R-> L? Pourquoi la matrice est 4x4 au lieu de 3x3 pour la transformation 2D? Les composants de changement de vitesse (12/-17?) Semblent trop petits. – MBo

+0

Références croisées: voir https://math.stackexchange.com/a/339033/35416 pour les étapes permettant de trouver la matrice en fonction de quatre points et de leurs images. La réponse et les commentaires incluent quelques démos JavaScript/CSS. – MvG

Répondre

0

Ce sont des coordonnées homogènes. Donc donné quelques [x1, y1, z1, 1] comme entrée, vous obtenez quelques [x2, y2, z2, w2] mais la position réelle qu'ils décrivent est [x2/w2, y2/w2, z2/w2], c'est-à-dire diviser par la dernière coordonnée.

Mais cela n'aboutit pas au résultat attendu. Il ne remplace pas non plus la matrice avec son adjuvant (ou son équivalent inverse), ni sa transposition. Les deux sont des conventions faciles à se tromper, donc sans trop réfléchir à la version que vous avez et devriez avoir, essayer les quatre alternatives (avec et sans adjonction, avec et sans transposition) résout un grand nombre de problèmes triviaux .

Mais pas le vôtre. Donc mon meilleur pari suivant serait que les coordonnées que vous attendez soient mesurées à partir d'un coin de l'image, alors que la propriété CSS transform-origin est à sa valeur initiale de 50% 50% 0 donc l'origine du système de coordonnées est en fait au centre de l'objet.

En fait, le partage du HTML et CSS pour cela pourrait avoir permis de vérifier cette hypothèse. Maintenant, vous devez vérifier si cela s'applique à vous. Je me souviens que lorsque j'ai créé a projective image transformation demo à answer a question about finding the transform, j'ai délibérément mis transform-origin: 0 0; (et les différentes versions préfixées par le vendeur) pour éviter de tels problèmes.

0

Merci beaucoup MvG.

-je suivre votre lien et je trouve ce que je veux [https://math.stackexchange.com/a/339033] Juste une chose, je dois inverser la matrice C pour trouver le pixel lié L < R

Je partage mon code pour donner une idée de ce que vous avez à faire vous pouvez trouver mon application dans la fonction 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>