首页 > 编程语言 >C#数字图像处理图像旋转图片加角度

C#数字图像处理图像旋转图片加角度

时间:2022-12-30 21:34:39浏览次数:78  
标签:dstBmp Stride C# srcBmpData 数字图像处理 Height Width srcBmp 图像

原文网址:https://www.cnblogs.com/-jingzhe/p/14271797.html

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

标签:dstBmp,Stride,C#,srcBmpData,数字图像处理,Height,Width,srcBmp,图像
From: https://www.cnblogs.com/bruce1992/p/17015845.html

相关文章

  • 【JetsonNano】移远EC200获取GPS定位及打电话
    硬件:JetsonNano、移远EC200模块操作系统:ubuntu18.041.安装驱动JstsonNano本身是没有USB转串口驱动的,所以我们需要先选择一个适合自己系统版本的驱动。1.1先通过unam......
  • AirBuddy for Mac(AirPods耳机管理工具)v2.6.3汉化版
    AirBuddy激活版哪里可以下载呢?AirBuddyforMac(AirPods耳机管理工具)v2.6.3汉化版分享给大家,Airbuddyformac是一款功能高效的AirPods耳机管理工具,可以帮助你体验AirPods......
  • MAC之PyQt5环境
    一,安装模块1,pyqt5pip3installpyqt52,pyqt5-toolspip3installpyqt5-tools二,pyqt5designer的位置安装了pyqt5后就有了:/Users/hz/WorkSpace/Python/Qt/venv/lib/python3.......
  • 软件icons图标大全(新增至2719枚大苏尔风格图标)下载
    想要获取海量图标,macw小编为大家分享一套mac电脑icons图标包,此套图标大全中包含两千多个.icns格式图片,这是一套不可多得的设计素材包。软件icons图标大全(新增至2719枚大......
  • 【归并排序】【链表】LeetCode 148. 排序链表
    题目链接148.排序链表思想分割cut环节:找到当前链表中点,并从中点将链表断开(以便在下次递归cut时,链表片段拥有正确边界)我们使用fast,slow快慢双指针法,奇数个......
  • #yyds干货盘点#linux cat命令详解
    cat命令:1、catlinux.txt:查看linux.txt内容。2、cat-nlinux.txt,查看linux.txt文件的内容,并且由1开始对所有输出行进行编号。(包括空白行)3、cat-blinux.txt,用法和-n......
  • Oracle_3_复制表、插入选择、递归查询
    一、复制表1、selectinto,使用查询结果新建表结构:createtable表名(字段名1,字段名2,......)asselect语句2、insertintoselect,使用查询结果插入到表中结构:inse......
  • 使用CSS提高网站性能的30种方法
    根据httparchive.org的页面重量报告,CSS在平均70个请求和2MB的网页上占7个HTTP请求和70Kb的代码。这并不是网站性能糟糕的最坏原因(我正看着你呢,JavaScript),但CSS面临着特定的......
  • git hook- prepare-commit-msg
    1.不能提交到masterproductionmain这几个分支2.分支名只能以feature|hotfix|bugfix|release|dev|improvement这几个开头3.自动加分支名到提交的消息上4.变基的情况......
  • C#开发PACS医学影像处理系统(十九):Dicom影像放大镜
    原文网址:https://www.cnblogs.com/Uncle-Joker/p/13690862.html在XAML代码设计器中,添加canvas画布与圆形几何对象,利用VisualBrush笔刷来复制画面内容到指定容器:<Canvas......