圆形鱼眼图像扭曲为平面图像

2024-01-08

截至 2015 年 11 月 12 日更新

我将 PanoTools 插件与 Photoshop 和 Hugin 一起使用,并使用了所有这些参数。最终我找到了满足我最低要求的投影、HFOV 和图像输出尺寸参数。

参数:

Processed Output: enter image description here

我的问题是如何将所有这些参数和值转换为 C# 算法编码,以便当我提供原始图像时,我将获得校正后的输出图像?

多谢。


我有一张从圆形鱼眼相机拍摄的方形图像。尺寸为2650*2650像素。

现在,我需要使用 C# 语言以编程方式将图像扭曲为平面全景图像。 我从互联网上查看了不同的算法示例下面的代码链接 http://www.helviojunior.com.br/fotografia/barrel-and-pincushion-distortion/ , Link1 https://stackoverflow.com/questions/2477774/correcting-fisheye-distortion-programmatically and Link2 http://paulbourke.net/dome/fish2/但就是无法成功。我的数学真的很糟糕,无法帮助我解决这个问题。希望有人能够指导我完成这个任务。 多谢。

相机输出图像的示例:

--Image grabbed from Wikipedia Fisheye Lens https://en.wikipedia.org/wiki/Fisheye_lens & size modified to fit my sample pixel. enter image description here

我尝试对其进行扭曲但没有成功的代码:

        Bitmap sourceImage = (Bitmap)Bitmap.FromFile("circularfisheye.jpg");
        double factor = 0.5;
        Boolean autoCrop = false;
        Color backgroundColor = Color.White;

        Bitmap StartImage = null;
        BitmapData srcBitmapData = null;
        Byte[] srcPixels = null;
        Byte[] dstPixels = null;
        Bitmap NewImage = null;
        BitmapData dstBitmapData = null;

        try
        {

            // Checks whether bpp ​​( Bits Per Pixel ) is 8 , 24, or 32
            int Depth = System.Drawing.Bitmap.GetPixelFormatSize(sourceImage.PixelFormat);
            if (Depth != 8 && Depth != 24 && Depth != 32)
            {
                throw new ArgumentException("Only 8, 24 and 32 bpp images are supported.");
            }

            // Retrieves the count of the color components
            int cCount = Depth / 8;

            Size baseSize = new Size(sourceImage.Width, sourceImage.Height);

            // check if a low image resize and need to improve the quality
            // and not generate image aliasing
            Int32 maxSize = Math.Max(sourceImage.Width, sourceImage.Height);
            if (maxSize < 3000)
            {
                float percent = 3000F / (float)maxSize;
                baseSize = new Size((Int32)((float)sourceImage.Width * percent), (Int32)((float)sourceImage.Height * percent));
            }

            StartImage = new Bitmap(baseSize.Width, baseSize.Height, sourceImage.PixelFormat);
            StartImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);

            // Create the drawing object and white background
            Graphics g = Graphics.FromImage(StartImage);
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.PixelOffsetMode = PixelOffsetMode.HighQuality;
            g.DrawImage(sourceImage, new Rectangle(-1, -1, baseSize.Width + 1, baseSize.Height + 1), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel);
            g.Dispose();
            // Locks the source image and copies it to the byte array and releases the source image
            srcBitmapData = StartImage.LockBits(new Rectangle(0, 0, StartImage.Width, StartImage.Height), ImageLockMode.ReadOnly, StartImage.PixelFormat);
            srcPixels = new byte[StartImage.Width * StartImage.Height * (Depth / 8)];
            Marshal.Copy(srcBitmapData.Scan0, srcPixels, 0, srcPixels.Length);
            StartImage.UnlockBits(srcBitmapData);
            srcBitmapData = null;

            // Create the target image byte array
            dstPixels = new Byte[srcPixels.Length];

            // Fill the entire frame with the selected background color
            Int32 index = ((1 * StartImage.Width) + 1) * cCount; //index = ((Y * Width) + X) * cCount
            do
            {
                if (Depth == 32) //For 32 bpp defines Red , Green, Blue and Alpha
                {
                    dstPixels[index++] = backgroundColor.B;
                    dstPixels[index++] = backgroundColor.G;
                    dstPixels[index++] = backgroundColor.R;
                    dstPixels[index++] = backgroundColor.A; // a
                }
                if (Depth == 24) //For 24 bpp defines Red , Green and Blue
                {
                    dstPixels[index++] = backgroundColor.B;
                    dstPixels[index++] = backgroundColor.G;
                    dstPixels[index++] = backgroundColor.R;
                }
                if (Depth == 8)
                // For 8 bpp defines the value of color ( Red , Green and Blue to be the same thing)
                {
                    dstPixels[index++] = backgroundColor.B;
                }

            } while (index < srcPixels.Length);
            // Calculate the maximum possible extent for the image and multiply by the desired factor
            double amp = 0;
            double ang = Math.PI * 0.5;
            for (Int32 a = 0; a < StartImage.Height; a++)
            {
                int y = (int)((StartImage.Height / 2) - amp * Math.Sin(ang));
                if ((y < 0) || (y > StartImage.Height))
                    break;
                amp = a;
            }
            amp = (amp - 2) * (factor < -1 ? -1 : (factor > 1 ? 1 : factor));
            // Define variables that calculates the cutoff points (if any)
            Int32 x1, y1, x2, y2;
            x1 = StartImage.Width;
            y1 = StartImage.Height;
            x2 = 0;
            y2 = 0;


            // Copy pixel by pixel for the new positions
            index = ((1 * StartImage.Width) + 1) * cCount;
            do
            {

                Int32 y = (Int32)((index / cCount) / StartImage.Width);
                Int32 x = (index / cCount) - (y * StartImage.Width);

                Point pt = NewPoint(new Point(x, y), StartImage.Width, StartImage.Height, amp, factor < 0);

                //Values ​​for crop
                if (factor >= 0)
                {
                    if (x == StartImage.Width / 2)
                    {
                        if (pt.Y < y1)
                            y1 = pt.Y;

                        if (pt.Y > y2)
                            y2 = pt.Y;
                    }

                    if (y == StartImage.Height / 2)
                    {
                        if (pt.X < x1)
                            x1 = pt.X;

                        if (pt.X > x2)
                            x2 = pt.X;
                    }
                }
                else
                {
                    if ((x == 1) && (y == 1))
                    {
                        y1 = pt.Y;
                        x1 = pt.X;
                    }

                    if ((x == StartImage.Width - 1) && (y == StartImage.Height - 1))
                    {
                        y2 = pt.Y;
                        x2 = pt.X;
                    }
                }

                //Bytes Index which will apply the pixel
                Int32 dstIndex = ((pt.Y * StartImage.Width) + pt.X) * cCount;

                if (Depth == 32)
                {
                    dstPixels[dstIndex] = srcPixels[index++];
                    dstPixels[dstIndex + 1] = srcPixels[index++];
                    dstPixels[dstIndex + 2] = srcPixels[index++];
                    dstPixels[dstIndex + 3] = srcPixels[index++]; // a
                }
                if (Depth == 24)
                {
                    dstPixels[dstIndex] = srcPixels[index++];
                    dstPixels[dstIndex + 1] = srcPixels[index++];
                    dstPixels[dstIndex + 2] = srcPixels[index++];
                }
                if (Depth == 8)
                {
                    dstPixels[dstIndex] = srcPixels[index++];
                }

            } while (index < srcPixels.Length);

            //Creates a new image based on the byte array previously created
            NewImage = new Bitmap(StartImage.Width, StartImage.Height, StartImage.PixelFormat);
            NewImage.SetResolution(StartImage.HorizontalResolution, StartImage.VerticalResolution);
            dstBitmapData = NewImage.LockBits(new Rectangle(0, 0, StartImage.Width, StartImage.Height), ImageLockMode.WriteOnly, StartImage.PixelFormat);
            Marshal.Copy(dstPixels, 0, dstBitmapData.Scan0, dstPixels.Length);
            NewImage.UnlockBits(dstBitmapData);


            //Generates the final image to crop or resize the real coo
            Bitmap FinalImage = new Bitmap(sourceImage.Width + 1, sourceImage.Height, StartImage.PixelFormat);
            NewImage.SetResolution(StartImage.HorizontalResolution, StartImage.VerticalResolution);

            Graphics g1 = Graphics.FromImage(FinalImage);
            g1.SmoothingMode = SmoothingMode.AntiAlias;
            g1.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g1.PixelOffsetMode = PixelOffsetMode.HighQuality;

            //Performs the cut if enabled automatic cutting and there is need to cut
            if ((autoCrop) && ((x1 > 0) || (y1 > 0) || (x2 < NewImage.Height) || (y2 < NewImage.Height)))
            {
                Rectangle cropRect = new Rectangle(x1, y1, x2 - x1, y2 - y1);
                g1.DrawImage(NewImage, new Rectangle(-1, -1, FinalImage.Width + 1, FinalImage.Height + 1), cropRect.X, cropRect.Y, cropRect.Width, cropRect.Height, GraphicsUnit.Pixel);
            }
            else
            {
                g1.DrawImage(NewImage, new Rectangle(-1, -1, FinalImage.Width + 1, FinalImage.Height + 1), 0, 0, NewImage.Width, NewImage.Height, GraphicsUnit.Pixel);
            }

            g1.Dispose();
            g1 = null;

            NewImage = null;
            FinalImage.Save("output.jpg");
            FinalImage.Dispose();
        }
        finally
        {
            srcBitmapData = null;
            srcPixels = null;
            dstPixels = null;
            dstBitmapData = null;
        }

这种扭曲就像旋转的对称性。

在极坐标中,极点位于图像中心,则表示为

r' = f(r)
Θ' = Θ

其中引号表示扭曲的坐标。函数 f 是未知的,应通过校准(查看常规目标)凭经验进行测量。

要校正图像,您需要反转函数 f 并将逆变换应用于图像。事实上,通过校准直接测量g更容易。作为起始近似值,一个简单的模型如

r = r' + a.r'³ 

can do.

您很可能没有用同一镜头拍摄的网格照片。最后的手段是通过可调整的参数来实现不失真功能,并通过反复试验来优化它们。

也应该可以通过查看直线的变形来推导出校准曲线,但这更“技术性”。


在笛卡尔坐标系中,您可以将校正变换表示为

x = g(r').x'/r'
y = g(r').y'/r'

where r' = √x'²+y'².

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

圆形鱼眼图像扭曲为平面图像 的相关文章

  • 如何使用 zlib 制作 .zip 文件

    我正在阅读zlib的文档 它相当详细 但我读到了这一行 输出数据将位于zlib格式 与 gzip 或zip formats http www zlib net zlib how html http www zlib net zlib how
  • C 程序从连接到系统的 USB 设备读取数据

    我正在尝试从连接到系统 USB 端口的 USB 设备 例如随身碟 获取数据 在这里 我可以打开设备文件并读取一些随机原始数据 但我想获取像 minicom teraterm 这样的数据 请让我知道我可以使用哪些方法和库来成功完成此操作以及如
  • 从多线程程序中调用 system()

    我们正在开发一个用 C 编写的多线程内存消耗应用程序 我们必须执行大量的 shellscript linux 命令 并获取返回码 读完之后article http www linuxprogrammingblog com threads a
  • 在 C# 中生成 HMAC-SHA1

    我正在尝试使用 C 来使用 REST API API 创建者提供了以下用于 hmac 创建的伪代码 var key1 sha1 body var key2 key1 SECRET KEY var key3 sha1 key2 var sig
  • C# 正则表达式用于查找 中具有特定结尾的链接

    我需要一个正则表达式模式来查找字符串 带有 HTML 代码 中的链接 以获取文件结尾如 gif 或 png 的链接 示例字符串 a href site com folder picture png target blank picture
  • 在 C# Winforms 应用程序中嵌入 Windows XP 主题

    我有一个旧版 C Windows 窗体应用程序 其布局是根据 Windows XP 默认主题设计的 由于需要将其作为 Citrix 应用程序进行分发 该应用程序现在看起来像经典主题应用程序 因为 Citrix 不鼓励使用主题系统服务 所以
  • 如何创建用于 QML 的通用对象模型?

    我想知道是否有任何宏或方法如何将 Qt 模型注册为 QObject 的属性 例如 我有AnimalModel http doc qt io qt 5 qtquick modelviewsdata cppmodels html qabstra
  • mprotect 之后 malloc 导致分段错误

    在使用 mprotect 保护内存区域后第一次调用 malloc 时 我遇到分段错误 这是执行内存分配和保护的代码片段 define PAGESIZE 4096 void paalloc int size Allocates and ali
  • 获取尚未实例化的类的函数句柄

    我对 C 相当陌生 我想做的事情可能看起来很复杂 首先 我想获取一些函数的句柄以便稍后执行它们 我知道我可以通过以下方式实现这一目标 List
  • 劫持系统调用

    我正在编写一个内核模块 我需要劫持 包装一些系统调用 我正在暴力破解 sys call table 地址 并使用 cr0 来禁用 启用页面保护 到目前为止一切顺利 一旦完成 我将公开整个代码 因此如果有人愿意 我可以更新这个问题 无论如何
  • HttpWebRequest vs Webclient(特殊场景)

    我知道这个问题之前已经回答过thread https stackoverflow com questions 1694388 webclient vs httpwebrequest httpwebresponse 但我似乎找不到详细信息 在
  • C++ 插件的“最适合”动态类型匹配

    我有一个几乎所有东西都是插件的架构 该架构以图形用户界面为基础 其中每个插件都由一个 表面 即用户可以通过其与插件交互的 UI 控件 表示 这些表面也是插件 每当添加新插件时 瘦主机都会自动确定哪个可用表面与其最匹配的 UI 如何在 C 中
  • 预处理后解析 C++ 源文件

    我正在尝试分析c 使用我定制的解析器的文件 写在c 在开始解析之前 我想摆脱所有 define 我希望源文件在预处理后可以编译 所以最好的方法是运行C Preprocessor在文件上 cpp myfile cpp temp cpp or
  • OpenCV 2.4.3 中的阴影去除

    我正在使用 OpenCV 2 4 3 最新版本 使用内置的视频流检测前景GMG http docs opencv org modules gpu doc video html highlight gmg gpu 3a 3aGMG GPU算法
  • C++ 错误 - “成员初始值设定项表达式列表被视为复合表达式”

    我收到一个我不熟悉的 C 编译器错误 可能是一个非常愚蠢的错误 但我不能完全指出它 Error test cpp 27 error member initializer expression list treated as compound
  • ASP.NET JQuery AJAX POST 返回数据,但在 401 响应内

    我的应用程序中有一个网页 需要调用我设置的 Web 服务来返回对象列表 这个调用是这样设置的 document ready function var response ajax type POST contentType applicati
  • 0-1背包算法

    以下 0 1 背包问题是否可解 浮动 正值和 浮动 权重 可以是正数或负数 背包的 浮动 容量 gt 0 我平均有 这是一个相对简单的二进制程序 我建议用蛮力进行修剪 如果任何时候你超过了允许的重量 你不需要尝试其他物品的组合 你可以丢弃整
  • 初始化 LPCTSTR /LPCWSTR [重复]

    这个问题在这里已经有答案了 我很难理解并使其正常工作 基本上归结为我无法成功初始化这种类型的变量 它需要有说的内容7 2E25DC9D 0 USB003 有人可以解释 展示这种类型的正确初始化和类似的值吗 我已查看此站点上的所有帮助 将项目
  • C 中带有指针的结构的内存开销[重复]

    这个问题在这里已经有答案了 我意识到当我的结构包含指针时 它们会产生内存开销 这里有一个例子 typedef struct int num1 int num2 myStruct1 typedef struct int p int num2
  • 类中不允许使用不完整类型,但类模板中允许使用不完整类型

    以下为无效代码 struct foo struct bar bar x error field x has incomplete type struct bar int value 42 int main return foo x valu

随机推荐

  • 元类冲突:基类和派生类具有不同的元类

    class AbstractBaseClass metaclass abc ABCMeta abc abstractmethod def someMethod class DerviedClass AbstractBaseClass met
  • Sqlite + Java:表未更新

    我正在使用 SQLite 的 Java 包装器 名为SQLiteJDBC http www zentus com sqlitejdbc 这可能会对任何答案产生一些影响 我有一个在 GUI 中显示的表 在该 UI 中 我有一个用于该表的单个行
  • 地址可达性 - 服务器和端口 - iOS 5

    我正在尝试检查服务器是否在线或离线 连接到服务器时我面临一个问题 即它有一个端口 我现在的代码 struct sockaddr in address address sin len sizeof address address sin fa
  • 需要帮助用delphi打印文本文件

    我正在尝试使用 Delphi 2010 打印文本文件 我找到了一些代码 但是当我运行时 它要求保存 xps 文件 但不显示打印对话框 代码位于http www delphipages com forum showthread php t 7
  • curl 可以工作,但不会在 BASH 脚本中执行

    以下curl 命令在命令行中运行 我从服务器得到了有效的响应 curl X POST https somebaseurl api v1 auth login H Content Type application json d email f
  • Jersey / ServletContext 和启动时加载资源

    我是 Java Web 开发领域的新手 我正在开发一个网络服务 我选择了 REST Jersey for it 我想在服务启动时初始化一些东西并保留它们 贯穿整个服务生命周期 第一个问题 构造函数是JerseyServlet 是做这件事的好
  • 解析 Facebook logInInBackgroundWithReadPermissions (Swift)

    我已成功设置 Parse 1 7 1 SDK 和 Facebook v4 SDK 设置桥接头文件和 AppDelegate swift 现在在我的 ViewController 中 我正在尝试创建 Facebook 登录 并且我正在尝试使用
  • read.csv 在 R 中警告“EOF 在引用的字符串中”,但在 EXCEL 中成功读取

    我尝试读取从下载的 csv 文件here https d396qusza40orc cloudfront net repdata 2Fdata 2FStormData csv bz2 我用下面的代码阅读 storm data read cs
  • 网络爬虫的典型礼貌因素?

    网络爬虫的典型礼貌因素是什么 除了始终遵守robot txt 禁止 和非标准 抓取延迟 但是 如果站点没有指定显式的抓取延迟 则默认值应该设置为多少 我们使用的算法是 If we are blocked by robots txt Make
  • RazorEngine 中的 using-Statement(没有 MVC 中的 HtmlHelper)

    我使用的是 RazorEngine 没有 MVC 框架 这意味着我没有用于创建模板的 HtmlHelper 没关系 反正我不需要它的任何方法 但我需要创建自己的方法 例如 BeginForm 现在这些都是用 HtmlHelper ViewC
  • 在 Chrome 上将 drawImage 与 Canvas 结合使用非常慢

    我一直在尝试使用drawImage 将SVG 文件的大量实例绘制到画布上 通过使用 SVG 作为源创建单个图像元素 然后对画布上的每个实例使用 drawImage 我希望即使有大量实例也可以非常快速地在画布中生成合成图像 就性能而言 这在
  • nt!KeWaitForSingleObject 不带参数

    我目前正在尝试调试系统死锁 但我很难理解这一点 Child SP RetAddr Args to Child Call Site fffff880 035cb760 fffff800 02ecef72 00000000 00000002 f
  • C++ SQL数据库比较[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 合并特定日期范围内的 Pandas DataFrame

    我有 2 个数据框 一个为Invoice Data另一个用于Promotion Dates Invoice Data数据框 LocationNo InvoiceDate InvoiceAmount A 01 Jul 20 79 B 01 J
  • 在 Firefox 中的新选项卡中打开链接

    我正在开发一个 Firefox 扩展 如何才能在新标签页中打开网页上的所有链接 这通常是 Firefox 中处理新链接的可配置选项 因此它们可能会用它覆盖您的扩展 然而 The code a href http www example co
  • Django自递归外键过滤器查询所有子项

    我有一个带有自引用外键关系的模型 class Person TimeStampedModel name models CharField max length 32 parent models ForeignKey self null Tr
  • ios UIImage 超出 UIImageView 边框

    这里黑色边框显示 UIImageView 的父 UIView 红色边框显示 UIImageView 我正在从服务器下载图像 但图像超出了 UIImageView 区域 如图所示 我正在以编程方式进行此操作 任何帮助将不胜感激 我在下面添加代
  • C# FTP,如何检查路径是文件还是目录?

    我有一个包含一些 FTP 路径的数组 如下所示 ftp ip 目录 目录1 ftp ip 目录 目录2 ftp ip 目录 文件 txt ftp ip 目录 directory3 ftp ip 目录 another file csv 如何确
  • 标准 C 中是否有推荐的整数类型来存储函数指针

    C99标准有uintptr t 一个推荐的整数类型 用于将数据指针 指向对象的指针 转换为 但我没有找到等效的整数类型来存储函数指针 是我忽略了吗 特定的编译器可以定义这样的类型 即使它不在标准中 但编译器更有可能声明函数指针可以存储在 例
  • 圆形鱼眼图像扭曲为平面图像

    截至 2015 年 11 月 12 日更新 我将 PanoTools 插件与 Photoshop 和 Hugin 一起使用 并使用了所有这些参数 最终我找到了满足我最低要求的投影 HFOV 和图像输出尺寸参数 参数 Processed Ou