zoukankan      html  css  js  c++  java
  • C#数字图像处理图像旋转图片加角度

    c#数字图像处理图像旋转

     

    如果平面上的点绕原点逆时针旋转θº,则其坐标变换公式为:

                                                                                           x'=xcosθ+ysinθ   y=-xsinθ+ycosθ

    其中,(x, y)为原图坐标,(x’, y’)为旋转后的坐标。它的逆变换公式为:

                                                                                           x=x'cosθ-y'sinθ   y=x'sinθ+y'cosθ

    矩阵形式为:

                                                                                         

    和缩放类似,旋转后的图像的像素点也需要经过坐标转换为原始图像上的坐标来确定像素值,同样也可能找不到对应点,因此旋转也用到插值法。在此选用性能较好的双线性插值法。为提高速度,在处理旋转90º、-90º、±180º时使用了镜像来处理。

     

    复制代码
            /// <summary>
            /// 图像旋转
            /// </summary>
            /// <param name="srcBmp">原始图像</param>
            /// <param name="degree">旋转角度</param>
            /// <param name="dstBmp">目标图像</param>
            /// <returns>处理成功 true 失败 false</returns>
            public static bool Rotation(Bitmap srcBmp, double degree, out Bitmap dstBmp)
            {
                if (srcBmp == null)
                {
                    dstBmp = null;
                    return false;
                }
                dstBmp = null;
                BitmapData srcBmpData = null;
                BitmapData dstBmpData = null;
                switch ((int)degree)
                {
                    case 0:
                        dstBmp = new Bitmap(srcBmp);
                        break;
                    case -90:
                        dstBmp = new Bitmap(srcBmp.Height, srcBmp.Width);
                        srcBmpData = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
                        dstBmpData = dstBmp.LockBits(new Rectangle(0, 0, dstBmp.Width, dstBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                        unsafe
                        {
                            byte* ptrSrc = (byte*)srcBmpData.Scan0;
                            byte* ptrDst = (byte*)dstBmpData.Scan0;
                            for (int i = 0; i < srcBmp.Height; i++)
                            {
                                for (int j = 0; j < srcBmp.Width; j++)
                                {
                                    ptrDst[j * dstBmpData.Stride + (dstBmp.Height - i - 1) * 3] = ptrSrc[i * srcBmpData.Stride + j * 3];
                                    ptrDst[j * dstBmpData.Stride + (dstBmp.Height - i - 1) * 3 + 1] = ptrSrc[i * srcBmpData.Stride + j * 3 + 1];
                                    ptrDst[j * dstBmpData.Stride + (dstBmp.Height - i - 1) * 3 + 2] = ptrSrc[i * srcBmpData.Stride + j * 3 + 2];
                                }
                            }
                        }
                        srcBmp.UnlockBits(srcBmpData);
                        dstBmp.UnlockBits(dstBmpData);
                        break;
                    case 90:
                        dstBmp = new Bitmap(srcBmp.Height, srcBmp.Width);
                        srcBmpData = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
                        dstBmpData = dstBmp.LockBits(new Rectangle(0, 0, dstBmp.Width, dstBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                        unsafe
                        {
                            byte* ptrSrc = (byte*)srcBmpData.Scan0;
                            byte* ptrDst = (byte*)dstBmpData.Scan0;
                            for (int i = 0; i < srcBmp.Height; i++)
                            {
                                for (int j = 0; j < srcBmp.Width; j++)
                                {
                                    ptrDst[(srcBmp.Width - j - 1) * dstBmpData.Stride + i * 3] = ptrSrc[i * srcBmpData.Stride + j * 3];
                                    ptrDst[(srcBmp.Width - j - 1) * dstBmpData.Stride + i * 3 + 1] = ptrSrc[i * srcBmpData.Stride + j * 3 + 1];
                                    ptrDst[(srcBmp.Width - j - 1) * dstBmpData.Stride + i * 3 + 2] = ptrSrc[i * srcBmpData.Stride + j * 3 + 2];
                                }
                            }
                        }
                        srcBmp.UnlockBits(srcBmpData);
                        dstBmp.UnlockBits(dstBmpData);
                        break;
                    case 180:
                    case -180:
                        dstBmp = new Bitmap(srcBmp.Width, srcBmp.Height);
                        srcBmpData = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
                        dstBmpData = dstBmp.LockBits(new Rectangle(0, 0, dstBmp.Width, dstBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                        unsafe
                        {
                            byte* ptrSrc = (byte*)srcBmpData.Scan0;
                            byte* ptrDst = (byte*)dstBmpData.Scan0;
                            for (int i = 0; i < srcBmp.Height; i++)
                            {
                                for (int j = 0; j < srcBmp.Width; j++)
                                {
                                    ptrDst[(srcBmp.Width - i - 1) * dstBmpData.Stride + (dstBmp.Height - j - 1) * 3] = ptrSrc[i * srcBmpData.Stride + j * 3];
                                    ptrDst[(srcBmp.Width - i - 1) * dstBmpData.Stride + (dstBmp.Height - j - 1) * 3 + 1] = ptrSrc[i * srcBmpData.Stride + j * 3 + 1];
                                    ptrDst[(srcBmp.Width - i - 1) * dstBmpData.Stride + (dstBmp.Height - j - 1) * 3 + 2] = ptrSrc[i * srcBmpData.Stride + j * 3 + 2];
                                }
                            }
                        }
                        srcBmp.UnlockBits(srcBmpData);
                        dstBmp.UnlockBits(dstBmpData);
                        break;
                    default://任意角度
                        double radian = degree * Math.PI / 180.0;//将角度转换为弧度
                                                                 //计算正弦和余弦
                        double sin = Math.Sin(radian);
                        double cos = Math.Cos(radian);
                        //计算旋转后的图像大小
                        int widthDst = (int)(srcBmp.Height * Math.Abs(sin) + srcBmp.Width * Math.Abs(cos));
                        int heightDst = (int)(srcBmp.Width * Math.Abs(sin) + srcBmp.Height * Math.Abs(cos));
    
                        dstBmp = new Bitmap(widthDst, heightDst);
                        //确定旋转点
                        int dx = (int)(srcBmp.Width / 2 * (1 - cos) + srcBmp.Height / 2 * sin);
                        int dy = (int)(srcBmp.Width / 2 * (0 - sin) + srcBmp.Height / 2 * (1 - cos));
    
                        int insertBeginX = srcBmp.Width / 2 - widthDst / 2;
                        int insertBeginY = srcBmp.Height / 2 - heightDst / 2;
    
                        //插值公式所需参数
                        double ku = insertBeginX * cos - insertBeginY * sin + dx;
                        double kv = insertBeginX * sin + insertBeginY * cos + dy;
                        double cu1 = cos, cu2 = sin;
                        double cv1 = sin, cv2 = cos;
    
                        double fu, fv, a, b, F1, F2;
                        int Iu, Iv;
                        srcBmpData = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
                        dstBmpData = dstBmp.LockBits(new Rectangle(0, 0, dstBmp.Width, dstBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    
                        unsafe
                        {
                            byte* ptrSrc = (byte*)srcBmpData.Scan0;
                            byte* ptrDst = (byte*)dstBmpData.Scan0;
                            for (int i = 0; i < heightDst; i++)
                            {
                                for (int j = 0; j < widthDst; j++)
                                {
                                    fu = j * cu1 - i * cu2 + ku;
                                    fv = j * cv1 + i * cv2 + kv;
                                    if ((fv < 1) || (fv > srcBmp.Height - 1) || (fu < 1) || (fu > srcBmp.Width - 1))
                                    {
    
                                        ptrDst[i * dstBmpData.Stride + j * 3] = 150;
                                        ptrDst[i * dstBmpData.Stride + j * 3 + 1] = 150;
                                        ptrDst[i * dstBmpData.Stride + j * 3 + 2] = 150;
                                    }
                                    else
                                    {//双线性插值
                                        Iu = (int)fu;
                                        Iv = (int)fv;
                                        a = fu - Iu;
                                        b = fv - Iv;
                                        for (int k = 0; k < 3; k++)
                                        {
                                            F1 = (1 - b) * *(ptrSrc + Iv * srcBmpData.Stride + Iu * 3 + k) + b * *(ptrSrc + (Iv + 1) * srcBmpData.Stride + Iu * 3 + k);
                                            F2 = (1 - b) * *(ptrSrc + Iv * srcBmpData.Stride + (Iu + 1) * 3 + k) + b * *(ptrSrc + (Iv + 1) * srcBmpData.Stride + (Iu + 1) * 3 + k);
                                            *(ptrDst + i * dstBmpData.Stride + j * 3 + k) = (byte)((1 - a) * F1 + a * F2);
                                        }
                                    }
                                }
                            }
                        }
                        srcBmp.UnlockBits(srcBmpData);
                        dstBmp.UnlockBits(dstBmpData);
                        break;
                }
                return true;
            }

    /// <summary>
    /// 获取方向
    /// </summary>
    /// <param name="p1"></param>
    /// <param name="p2"></param>
    /// <returns></returns>
    private double GetAtan(ZDPoint p1, ZDPoint p2)
    {
    double jiaodu = Math.Atan2((p2.Y - p1.Y), (p2.X - p1.X)) * 180 / Math.PI;
    return jiaodu;
    }

    复制代码

     

    https://www.cnblogs.com/dearzhoubi/p/8663596.html

  • 相关阅读:
    HDU 1358 Period (KMP)
    POJ 1042 Gone Fishing
    Csharp,Javascript 获取显示器的大小的几种方式
    css text 自动换行的实现方法 Internet Explorer,Firefox,Opera,Safar
    Dynamic Fonts动态设置字体大小存入Cookie
    CSS Image Rollovers翻转效果Image Sprites图片精灵
    CSS three column layout
    css 自定义字体 Internet Explorer,Firefox,Opera,Safari
    颜色选择器 Color Picker,Internet Explorer,Firefox,Opera,Safar
    CSS TextShadow in Safari, Opera, Firefox and more
  • 原文地址:https://www.cnblogs.com/-jingzhe/p/14271797.html
Copyright © 2011-2022 走看看