• 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

  • 相关阅读:
    css最简单的在背景图片上显示模糊背景色的方法
    css添加网格背景
    获取bing必应图片
    JavaScript超过一定高度导航添加类名
    6行css就可以解决的瀑布流布局的方法
    css实现背景图横向滚动
    JavaScript根据一个元素的显示隐藏控制另一个元素的显示和隐藏
    JavaScript判断地址栏链接与导航栏链接是否一致并给导航添加class
    JavaScript实现选中文字自动复制
    Day 74 算法基础(二)
  • 原文地址:https://www.cnblogs.com/-jingzhe/p/14271797.html
Copyright © 2020-2023  润新知