机器视觉入门之路(十七,完成图像旋转(再看微软魔法!),c#)

以下是未旋转,加载的8位图像(大小,256*256),显示用24位,正常:

再看一眼中心旋转后的8位图像(大小改变,362*362),显示用8位(西游记里妖怪对孙大圣使出的绝招妖法):

再看一眼中心旋转后的8位图像(大小改变,362*362),显示用24位:

再看一眼中心旋转后的8位图像(大小改变,362*362),显示用32位:

图像中心旋转,c#代码如下(与c++保持一致,旋转的是32位图像):

 //旋转后放入picturebox2
  // 原始图像四个角的坐标
  int srcX1, srcX2, srcX3, srcX4;
  int srcY1, srcY2, srcY3, srcY4;

  srcX1 = 0;
  srcY1 = 0;
  //srcX2 = w - 1;
  srcX2 = 256 - 1;
  srcY2 = 0;
  srcX3 = 0;
  //srcY3 = h - 1;
  //srcX4 = w - 1;
  //srcY4 = h - 1;
  srcY3 = 256 - 1;
  srcX4 =256 - 1;
  srcY4 = 256 - 1;
  // 计算旋转角度的正弦和余弦值
  double fsin = Math.Sin(0.78);//近似45度
  double fcos = Math.Cos(0.78);
  // 图像经过旋转后四个角的坐标
  double desX1, desX2, desX3, desX4;
  double desY1, desY2, desY3, desY4;

  desX1 = fcos * srcX1 + fsin * srcY1;
  desY1 = -fsin * srcX1 + fcos * srcY1;
  desX2 = fcos * srcX2 + fsin * srcY2;
  desY2 = -fsin * srcX2 + fcos * srcY2;
  desX3 = fcos * srcX3 + fsin * srcY3;
  desY3 = -fsin * srcX3 + fcos * srcY3;
  desX4 = fcos * srcX4 + fsin * srcY4;
  desY4 = -fsin * srcX4 + fcos * srcY4;

  /*int*/
int  outwidth = (int)(max(Math.Abs(desX4 - desX1), Math.Abs(desX3 - desX2)) + 0.5);
  /*int*/
 int  outheight = (int)(max(Math.Abs(desY4 - desY1), Math.Abs(desY3 - desY2)) + 0.5);

 byte[] image1 = new byte[outwidth * outheight * 4];
// byte[] image1 = new byte[outwidth * outheight*3 ];

// byte[] image1 = new byte[outwidth * outheight ];
 // memset(image1, 255, outwidth * outheight * 4);

  //double num1 = -0.5 * outwidth * fcos - 0.5 * outheight * fsin + 0.5 * w;
  //double num2 = 0.5 * outwidth * fsin - 0.5 * outheight * fcos + 0.5 * h;
  double num1 = -0.5 * outwidth * fcos - 0.5 * outheight * fsin + 0.5 * 256;
  double num2 = 0.5 * outwidth * fsin - 0.5 * outheight * fcos + 0.5 * 256;

  //BYTE* copypixel = NULL;
  //BYTE* objpixel = NULL;
  int x = 0;
  int y = 0;

  for (int j = 0; j < outheight; j++)
      for (int i = 0; i < outwidth; i++)
      {
          x = (int)(i * fcos + j * fsin + num1 + 0.5);
          y = (int)(-i * fsin + j * fcos + num2 + 0.5);

          //if (x == w)
          if (x == 256)
              x--;
          //if (y == h)
          if (y == 256)
              y--;

          //copypixel = image0 + y * w * 4 + x * 4;//原图像
          //objpixel = image1 + j * outwidth * 4 + i * 4;//中心旋转后图像

          //if (x >= 0 && x < w && y >= 0 && y < h)
          //    memcpy(objpixel, copypixel, 4);
          if (x >= 0 && x < 256 && y >= 0 && y < 256)
          {
              int temp = j * outwidth + i;
              //image1[temp ] = glob_buffer8[y * 256 + x];
              image1[temp * 4] = glob_buffer8[y * 256 + x];
              image1[temp * 4 + 1] = glob_buffer8[y * 256 + x];
              image1[temp * 4+ 2] = glob_buffer8[y * 256 + x];
              image1[temp * 4 + 3] = 255;
          }                                   
      }

你用c++代码测试,也是一样的,这神奇的微软!微软也是一脉相承,保持一致啊!

多年前已经遇到这个问题,借今天这个机会,美妙的回忆一下曾经的迷茫的自己,算法是没有问题的,关键是微软这神奇的gdi显示,你占位(分8,24,32位)不够,一边歇菜去吧!(详细对比代码请看:机器视觉入门之路(十九,图像旋转之后,c#))

这不是西安泡馍的技法吗?粗人掰馍,师傅粗制;你细掰馍,师傅细制作!哈哈!

需要强调的是:(x0,y0,1)\begin{bmatrix}1 ,0 ,0\\ 0 ,1 ,0\\\Delta x,\Delta y, 1 \end{bmatrix}*\begin{bmatrix} cos\Theta ,-sin\Theta ,0\\ sin\Theta ,cos\Theta ,0\\0,0, 1 \end{bmatrix}\begin{bmatrix}1 ,0 ,0\\ 0 ,1 ,0\\-\Delta x,-\Delta y, 1 \end{bmatrix}=(x,y,1)

这个公式在这个例子中的运算是,平移(-128,-128),旋转0.78弧度,再平移(181,181):

(x0,y0,1)\begin{bmatrix}1 ,0 ,0\\ 0 ,1 ,0\\-128,-128, 1 \end{bmatrix}*\begin{bmatrix} cos(0.78) ,-sin(0.78) ,0\\ sin(0.78) ,cos(0.78) ,0\\0,0, 1 \end{bmatrix}\begin{bmatrix}1 ,0 ,0\\ 0 ,1 ,0\\181,181, 1 \end{bmatrix}=(x,y,1)

原因是,第一幅图中心(128,128),旋转后图像又256*256变为362*362,中心在(181,181)处。