空间域图像卷积

2023-12-26

我正在尝试复制结果这个链接 https://stackoverflow.com/q/38709810/159072 using linear卷积于空间域.

图像首先转换为二维double数组,然后进行卷积。图像和内核大小相同。图像在卷积之前进行填充,并在卷积之后进行相应的裁剪。

与基于 FFT 的卷积相比,输出很奇怪并且不正确.

我该如何解决这个问题?

请注意,我从 Matlab 获得了以下图像输出,它与我的 C# FFT 输出相匹配:

.

Update-1: Following @Ben Voigt's comment, I changed the Rescale() function to replace 255.0 with 1 and thus the output is improved substantially. But, still, the output doesn't match the FFT output (which is the correct one).
enter image description here

.

Update-2: Following @Cris Luengo's comment, I have padded the image by stitching and then performed spatial convolution. The outcome has been as follows:
enter image description here

So, the output is worse than the previous one. But, this has a similarity with the 2nd output of the linked answer https://stackoverflow.com/a/38724731/159072 which means a circular convolution is not the solution.

.

Update-3: I have used the Sum() function proposed by @Cris Luengo's answer. The result is a more improved version of **Update-1**:
enter image description here

But, it is still not 100% similar to the FFT version.

.

Update-4: Following @Cris Luengo's comment, I have subtracted the two outcomes to see the difference:
enter image description here, enter image description here

1. spatial minus frequency domain
2. frequency minus spatial domain

Looks like, the difference is substantial which means, spatial convolution is not being done correctly.

.

源代码:

(Notify me if you need more source code to see.)

    public static double[,] LinearConvolutionSpatial(double[,] image, double[,] mask)
    {
        int maskWidth = mask.GetLength(0);
        int maskHeight = mask.GetLength(1);

        double[,] paddedImage = ImagePadder.Pad(image, maskWidth);

        double[,] conv = Convolution.ConvolutionSpatial(paddedImage, mask);

        int cropSize = (maskWidth/2);

        double[,] cropped = ImageCropper.Crop(conv, cropSize);

        return conv;
    } 
    static double[,] ConvolutionSpatial(double[,] paddedImage1, double[,] mask1)
    {
        int imageWidth = paddedImage1.GetLength(0);
        int imageHeight = paddedImage1.GetLength(1);

        int maskWidth = mask1.GetLength(0);
        int maskHeight = mask1.GetLength(1);

        int convWidth = imageWidth - ((maskWidth / 2) * 2);
        int convHeight = imageHeight - ((maskHeight / 2) * 2);

        double[,] convolve = new double[convWidth, convHeight];

        for (int y = 0; y < convHeight; y++)
        {
            for (int x = 0; x < convWidth; x++)
            {
                int startX = x;
                int startY = y;

                convolve[x, y] = Sum(paddedImage1, mask1, startX, startY);
            }
        }

        Rescale(convolve);

        return convolve;
    } 

    static double Sum(double[,] paddedImage1, double[,] mask1, int startX, int startY)
    {
        double sum = 0;

        int maskWidth = mask1.GetLength(0);
        int maskHeight = mask1.GetLength(1);

        for (int y = startY; y < (startY + maskHeight); y++)
        {
            for (int x = startX; x < (startX + maskWidth); x++)
            {
                double img = paddedImage1[x, y];
                double msk = mask1[x - startX, y - startY];
                sum = sum + (img * msk);
            }
        }

        return sum;
    }

    static void Rescale(double[,] convolve)
    {
        int imageWidth = convolve.GetLength(0);
        int imageHeight = convolve.GetLength(1);

        double maxAmp = 0.0;

        for (int j = 0; j < imageHeight; j++)
        {
            for (int i = 0; i < imageWidth; i++)
            {
                maxAmp = Math.Max(maxAmp, convolve[i, j]);
            }
        }

        double scale = 1.0 / maxAmp;

        for (int j = 0; j < imageHeight; j++)
        {
            for (int i = 0; i < imageWidth; i++)
            {
                double d = convolve[i, j] * scale;
                convolve[i, j] = d;
            }
        }
    } 

    public static Bitmap ConvolveInFrequencyDomain(Bitmap image1, Bitmap kernel1)
    {
        Bitmap outcome = null;

        Bitmap image = (Bitmap)image1.Clone();
        Bitmap kernel = (Bitmap)kernel1.Clone();

        //linear convolution: sum. 
        //circular convolution: max
        uint paddedWidth = Tools.ToNextPow2((uint)(image.Width + kernel.Width));
        uint paddedHeight = Tools.ToNextPow2((uint)(image.Height + kernel.Height));

        Bitmap paddedImage = ImagePadder.Pad(image, (int)paddedWidth, (int)paddedHeight);
        Bitmap paddedKernel = ImagePadder.Pad(kernel, (int)paddedWidth, (int)paddedHeight);

        Complex[,] cpxImage = ImageDataConverter.ToComplex(paddedImage);
        Complex[,] cpxKernel = ImageDataConverter.ToComplex(paddedKernel);

        // call the complex function
        Complex[,] convolve = Convolve(cpxImage, cpxKernel);

        outcome = ImageDataConverter.ToBitmap(convolve);

        outcome = ImageCropper.Crop(outcome, (kernel.Width/2)+1);

        return outcome;
    } 

您当前的输出看起来更像是自相关函数,而不是 Lena 与她自己的卷积。我认为问题可能出在你的身上Sum功能。

如果你看一下 的定义卷积和 https://en.wikipedia.org/wiki/Convolution#Discrete_convolution,您将看到内核(或映像,无关紧要)已镜像:

sum_m( f[n-m] g[m] )

对于单一函数,m出现一个加号,而另一个出现一个减号。

您需要修改您的Sum函数来读取mask1图像按正确顺序排列:

static double Sum(double[,] paddedImage1, double[,] mask1, int startX, int startY)
{
    double sum = 0;

    int maskWidth = mask1.GetLength(0);
    int maskHeight = mask1.GetLength(1);

    for (int y = startY; y < (startY + maskHeight); y++)
    {
        for (int x = startX; x < (startX + maskWidth); x++)
        {
            double img = paddedImage1[x, y];
            double msk = mask1[maskWidth - x + startX - 1, maskHeight - y + startY - 1];
            sum = sum + (img * msk);
        }
    }

    return sum;
}

另一种选择是传递镜像版本mask1到这个函数。

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

空间域图像卷积 的相关文章

随机推荐

  • 在预制件中存储对场景对象的引用?

    看 我的场景中有一个玩家和一个敌人 我正在使用 vector2 movetowards 将敌人移向我的玩家 但我的敌人是一个预制件 所以我必须在检查器中给它一个我的玩家的引用作为目标 但是当我从场景中删除敌人时 因为它是一个预制件 它会删除
  • 当表单经过身份验证的用户未经身份验证时捕获的事件

    我基本上正在寻找与 FormsAuthentication OnAuthenticate 相反的事件 我想在用户注销时从数据库中删除一些值 我尝试将其放入 Session End 事件中 但在执行此事件时用户似乎已经离开了 更新 如果我无法
  • 如何返回作为参数给出的相同集合类型,但具有不同的元素类型?

    我想做这个 public
  • 为什么像 Ruby 和 Python 这样的动态语言不像 Java 或 C# 那样有接口的概念?

    令我惊讶的是 我对 Ruby 和 Python 等动态语言越来越感兴趣 他们声称它们是 100 面向对象的 但正如我所读到的 接口 方法重载 运算符重载等几个基本概念都缺失了 它是否以某种方式内置在幕后 或者这些语言只是不需要它 如果后者是
  • Python 电子邮件负载解码

    我知道这个问题已经被问了上千次了 但我已经快要崩溃了 所以我忍不住去寻求帮助 我有一封带有法国口音的电子邮件 这句话是 席琳 柏林安妮特 0633 python的email包变化 在 3A 上 E9 上的 如何恢复口音 和 符号 我通过网络
  • 奇异值分解实现

    我有一个用 C 实现的 SVD 库 但我想在 Java 程序中调用它的函数 有没有简单的方法可以做到这一点 或者有人建议一个 Java 中 SVD 实现的链接 还有 Apache commons Math 库 http commons ap
  • Android 深度链接架构:同时匹配 http 和 https

    我希望我的应用程序能够打开http www example com and https www example com 这有效
  • 音频单元图暂停和重复

    我一直在尝试使用 Apple 提供的代码来实现音频单元图 IphoneMixerEQGraph测试 http developer apple com library ios samplecode iPhoneMixerEQGraphTest
  • Typescript 与“typeof”相反/反向操作

    Angular 可以按类型查询子组件 在测试中使用它 如下所示 fixture debugElement query By directive ComponentType 现在我想创建一个为我执行此操作的函数 import Componen
  • 从其他类 Objective-C 访问方法

    寻找这个问题的答案 但我还没有找到合适的答案 我希望你们 和女孩 能帮助我 这是针对 iPhone 应用程序的 好吧 我有一个多视图应用程序 每个视图都有自己的类 一切都很愉快 然而 不同的类有时会调用相同的方法 到目前为止 我只是在两个类
  • 尝试批量插入行时发生 Knexjs 错误:获取连接超时。泳池可能已经满了。

    完整错误 Knex 获取连接超时 池可能已满 您是否缺少 transacting trx 调用 我有一个超过 70k 行的 csv json 插入 15k 17k 次后 它停止并抛出上述错误 代码如下 csvtojson colParser
  • Microsoft Graph API 是否支持 Azure AD B2C 的更改通知?

    我正在尝试获取更改通知 以便用户使用连接到 Azure AD B2C 的应用程序 我按照以下教程操作并成功创建了订阅 但我从未收到任何更改通知 https learn microsoft com en us learn modules ms
  • 如何存储长符号计算的结果以供以后使用?

    我的计算是这样的 f x runs fast g x runs fast h x depends on f x g x runs slow 5mins 现在我只需要结果h x 每次我重新启动 mma 时 我基本上都会重做相同的计算以获得h
  • 将 JSON 转换为 .NET 数据集

    我正在编写一个 Java servlet 它使用http json org java http json org java 用于从 mssql 数据库读取一些数据并将结果集转换为 JSON 字符串的库 NET 客户端应用程序正在使用此 JS
  • 如何在Word宏中的TextBox中插入文本

    我在Word中创建了一个文本框 我想在其中插入文本 Sub k Dim Box As Shape Set Box ActiveDocument Shapes AddTextbox Orientation msoTextOrientation
  • 如何在谷歌地图 API v3 中一次仅显示一个信息窗口

    我们可以在谷歌地图中一次仅显示一个信息窗口 并为多个标记显示多个信息窗口吗 意味着 当我单击标记时隐藏 关闭其他信息窗口并仅显示当前标记信息窗口 Thanks 我解决的方法如下 var infoWindowsOpenCurrently A
  • C# 在方法或事件处理程序之间传递变量

    我仍在尝试学习 c 我的问题是如何将变量从 Item1 Click 传递到 Item2 Click 这与在方法之间传递它们是同一件事还是因为它们是事件处理程序而有所不同 public partial class Events System
  • K&R 第 2 版,示例 1.9 字符数组

    我对以下代码中的 getline 函数和参数定义有疑问 代码直接取自 K R 第 1 9 章 字符数组 我已将其逐字复制在这里 问题是 当我按原样编译程序时 出现三个错误 我在最后重现了这些错误 当我在出现错误的三个地方将函数和函数参数定义
  • 从 sql 修改 SSIS 目录中的连接管理器信息

    有没有办法在使用 sql 代码部署后从 ssis 目录更新连接管理器信息 我想先部署没有敏感数据的项目 执行目录 deploy project 然后通过 SQL 将用户名和密码添加到 SSIS 目录项目 有没有办法从以下位置更新连接管理器信
  • 空间域图像卷积

    我正在尝试复制结果这个链接 https stackoverflow com q 38709810 159072 using linear卷积于空间域 图像首先转换为二维double数组 然后进行卷积 图像和内核大小相同 图像在卷积之前进行填