图像处理与计算机视觉编程实战

table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1rem;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
pre {
background-color: #f8f8f8;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
}

1、某特定数码相机的图像传感器包含2016×3024个像素。该传感器的几何形状与传统35毫米相机(图像尺寸为24×36毫米)相同,只是小1.6倍。计算该数字传感器的分辨率(以每英寸点数dpi为单位)。

需先计算出传感器实际尺寸,

– 长为 24 ÷ 1.6 = 15 mm,

– 宽为 36 ÷ 1.6 = 22.5 mm;

再将毫米换算为英寸,

– 长 15 ÷ 25.4 ≈ 0.59 英寸,

– 宽 22.5 ÷ 25.4 ≈ 0.89 英寸;

最后计算分辨率,

– 水平分辨率为 2016 ÷ 0.59 ≈ 3417 dpi,

– 垂直分辨率为 3024 ÷ 0.89 ≈ 3400 dpi,

所以该数字传感器分辨率约为

3400 – 3417 dpi

2、确定存储一个大小为 4000×3000 像素的未压缩二值图像所需的字节数。

因为二值图像每个像素通常用 1 位(bit)编码,4000×3000 像素的图像总位数为 4000×3000×1 = 12000000 位。又因为 8 位等于 1 字节(Byte),所以所需字节数为 12000000÷8 = 1500000 字节。

3、计算使用每个颜色通道8位、10位、12位和14位来存储一个大小为640×480像素的未压缩RGB彩色图像所需的字节数。

每个颜色通道8位时:640×480×3×8÷8 = 921600字节;

每个颜色通道10位时:640×480×3×10÷8 = 1152000字节;

每个颜色通道12位时:640×480×3×12÷8 = 1382400字节;

每个颜色通道14位时:640×480×3×14÷8 = 1612800字节。

4、编写一个新的 ImageJ 插件,将 8 位灰度图像水平循环移动,直到恢复到原始状态。为了在每次移动后显示修改后的图像,需要一个对相应 ImagePlus 对象的引用(ImageProcessor 没有显示方法)。ImagePlus 对象只能在插件的 setup() 方法中访问,该方法会在 run() 方法之前自动调用。请实现这个插件。

以下是根据要求编写的 Java 代码示例:


import ij.ImagePlus;
import ij.plugin.filter.PlugInFilter;
import ij.process.ImageProcessor;

public class XY_Plugin implements PlugInFilter {
    ImagePlus im;

    public int setup(String args, ImagePlus im) {
        this.im = im;
        return DOES_8G;
    }

    public void run(ImageProcessor ip) {
        int width = ip.getWidth();
        for (int shift = 0; shift < width; shift++) {
            // 创建一个新的 ImageProcessor 用于存储移动后的图像
            ImageProcessor newIp = ip.duplicate();
            for (int y = 0; y < ip.getHeight(); y++) {
                for (int x = 0; x < width; x++) {
                    int newX = (x + shift) % width;
                    int pixel = ip.get(x, y);
                    newIp.set(newX, y, pixel);
                }
            }
            // 将移动后的图像复制回原始 ImageProcessor
            ip.insert(newIp, 0, 0);
            // 重新绘制图像
            im.updateAndDraw();
            try {
                // 可以调整延迟时间以控制动画速度
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

上述代码实现了将 8 位灰度图像水平循环移动,直到恢复到原始状态,并在每次移动后显示修改后的图像。

5、开发一个 ImageJ 插件,使用 Java 方法 Math.random() 或 Random.nextInt(int n) 创建一个像素值在 [0, 255] 范围内均匀分布的图像。分析该图像的直方图,以确定像素值的实际分布均匀程度。

以下是一个满足需求的 ImageJ 插件示例代码:


import ij.IJ;
import ij.ImagePlus;
import ij.plugin.filter.PlugInFilter;
import ij.process.ImageProcessor;
import java.util.Random;

public class RandomImageGenerator implements PlugInFilter {
    public int setup(String arg, ImagePlus img) {
        return DOES_8G + NO_CHANGES;
    }

    public void run(ImageProcessor ip) {
        int width = ip.getWidth();
        int height = ip.getHeight();
        Random random = new Random();
        // 为图像的每个像素设置随机值
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int randomValue = random.nextInt(256); // 生成 0 到 255 之间的随机整数
                ip.set(x, y, randomValue);
            }
        }
        // 计算并显示直方图
        int[] histogram = ip.getHistogram();
        for (int i = 0; i < 256; i++) {
            IJ.log("Intensity " + i + ": " + histogram[i]);
        }
    }
}

代码说明:


插件设置


setup

方法返回

DOES_8G + NO_CHANGES

,表明该插件需要一个 8 位灰度图像且不会修改它。


生成随机图像

:在

run

方法中,使用

Random

类的

nextInt(256)

方法为图像的每个像素生成一个 0 到 255 之间的随机整数。


计算并显示直方图

:使用

ip.getHistogram()

方法计算图像的直方图,并通过

IJ.log

方法输出每个强度值的像素计数。

分析像素值分布均匀程度:

通过查看输出的直方图,可以观察每个强度值的像素计数。如果像素值是均匀分布的,每个强度值的像素计数应该大致相等。可以进一步计算每个强度值的频率,并与理论上的均匀分布频率(即 1/256)进行比较,以评估分布的均匀程度。

6、开发一个 ImageJ 插件,创建一个具有高斯(正态)分布的随机图像,其均值 μ = 128,标准差 σ = 50。使用标准 Java 方法 double Random.nextGaussian() 生成正态分布的随机数(均值 μ = 0,标准差 σ = 1),并将其适当地缩放为像素值。分析生成图像的直方图,查看它是否也呈现高斯分布。

以下是实现该功能的 ImageJ 插件代码示例:


import ij.IJ;
import ij.ImagePlus;
import ij.plugin.filter.PlugInFilter;
import ij.process.FloatProcessor;
import java.util.Random;

public class GaussianRandomImagePlugin implements PlugInFilter {
    public int setup(String arg, ImagePlus img) {
        return DOES_32;
    }

    public void run(ij.process.ImageProcessor ip) {
        int width = ip.getWidth();
        int height = ip.getHeight();
        FloatProcessor fp = (FloatProcessor) ip;
        Random rg = new Random();
        double mean = 128;
        double stdDev = 50;
        for (int v = 0; v < height; v++) {
            for (int u = 0; u < width; u++) {
                double randomValue = rg.nextGaussian() * stdDev + mean;
                fp.setf(u, v, (float) randomValue);
            }
        }
        // 分析直方图
        int[] h = new int[256];
        for (int v = 0; v < height; v++) {
            for (int u = 0; u < width; u++) {
                int i = (int) fp.getf(u, v);
                if (i >= 0 && i < 256) {
                    h[i] = h[i] + 1;
                }
            }
        }
        // 打印直方图信息
        for (int i = 0; i < 256; i++) {
            IJ.log("Intensity " + i + ": " + h[i]);
        }
    }
}

此代码创建了一个 ImageJ 插件,生成具有指定均值和标准差的高斯分布随机图像,并分析其直方图。可以将代码保存为

.java

文件,然后在 ImageJ 中编译运行。运行后,插件会生成图像并在日志中输出直方图信息,通过分析日志中的直方图信息,可查看是否呈现高斯分布。

7、证明标准盒式滤波器不是各向同性的(即不能在所有方向上对图像进行相同的平滑处理)。

标准盒式滤波器形状为矩形,在频率空间有剧烈行为,会产生强烈的“振铃”现象。且它对滤波器区域内所有图像像素赋予相同权重,没有对靠近滤波器中心的像素给予更强的权重,不能在各个方向上均匀地进行平滑处理,所以

不是各向同性的

8、设计一个线性滤波器(内核),使其在水平方向上产生7个像素长度的模糊效果,从而模拟曝光期间相机移动的效果。

要实现水平方向7个像素长度的模糊,可设计一个1×7的滤波器内核,让这7个像素具有相同权重。滤波器内核H为:

H=[17 17 17 17 17 17 17]H=[17 17 17 17 17 17 17]

因为每个像素对结果的贡献为其值的七分之一。

9、比较5×5、11×11、25×25和51×51像素的非可分离线性滤波器和x/y可分离滤波器所需的处理步骤数。计算每种情况下可分离性带来的速度提升。

对于非可分离线性滤波器,处理步骤数为滤波器尺寸的乘积;对于x/y可分离滤波器,处理步骤数为滤波器两个边长之和。速度提升为非可分离滤波器处理步骤数与可分离滤波器处理步骤数的比值。


5×5滤波器



– 非可分离处理步骤数为 5×5 = 25 步

– 可分离处理步骤数为 5 + 5 = 10 步

– 速度提升为 25 ÷ 10 = 2.5 倍


11×11滤波器



– 非可分离处理步骤数为 11×11 = 121 步

– 可分离处理步骤数为 11 + 11 = 22 步

– 速度提升为 121 ÷ 22 = 5.5 倍


25×25滤波器



– 非可分离处理步骤数为 25×25 = 625 步

– 可分离处理步骤数为 25 + 25 = 50 步

– 速度提升为 625 ÷ 50 = 12.5 倍


51×51滤波器



– 非可分离处理步骤数为 51×51 = 2601 步

– 可分离处理步骤数为 51 + 51 = 102 步

– 速度提升为 2601 ÷ 102 ≈ 25.5 倍

10、为灰度图像实现一个圆形(即圆盘形)中值滤波器。使滤波器的半径r在1到10像素的范围内可调节。使用一个二进制(0/1)圆盘形掩码来表示滤波器的支撑区域R,其最小尺寸为(2r + 1) × (2r + 1)。为所选的滤波器半径r动态创建这个掩码。

在实际实现该功能时,需要使用具有图像处理能力的编程环境,如Java结合ImageJ插件开发环境。以下是实现该功能的主要步骤:

编写一个ImageJ插件类。

使用

GenericDialog

类创建一个对话框,让用户输入半径

r

(范围在1到10之间)。

根据用户输入的半径

r

,动态创建一个大小为

(2r + 1) × (2r + 1)

的二进制圆盘形掩码。

对灰度图像应用该圆盘形中值滤波器,根据掩码处理每个像素。

返回处理后的图像。

在代码实现中,需要注意掩码的创建逻辑,确保其为圆盘形状。同时,在应用滤波器时,要正确处理图像边界情况。由于篇幅限制,无法提供完整代码,但可以根据上述步骤逐步实现该功能。

11、用户选择的感兴趣区域(ROI)标记了图像中应保持清晰的部分。通过应用宽度为σ1的高斯滤波器创建图像I的模糊副本˜I。使用FloatProcessor从选定的ROI创建二值掩码图像R,其中ROI内的所有像素值设为1,其他像素设为0。应用宽度为图像宽度5%的另一个高斯滤波器对掩码图像R进行模糊处理,得到模糊掩码˜R。使用模糊掩码˜R的值以I′ ←˜R · I+(1 −˜R) · ˜I的形式组合(混合)图像I和˜I。请简述上述操作的步骤。

该描述是关于模拟景深效果的图像处理步骤:

用户选择感兴趣区域(ROI),该区域在最终图像中保持清晰;

对原始图像 $ I $ 应用宽度为 $ sigma_1 $ 的高斯滤波器,得到模糊图像 $ ilde{I} $;

从ROI创建二值掩码图像 $ R $,ROI内像素值为1,其他为0;

对掩码图像 $ R $ 应用宽度为图像宽度5%的高斯滤波器,得到模糊掩码 $ ilde{R} $;

利用模糊掩码 $ ilde{R} $ 混合图像 $ I $ 和 $ ilde{I} $,得到最终部分模糊的图像 $ I’ $。

12、基于以下(水平和垂直)滤波器对实现“优化的索贝尔”边缘算子:Hx = [-3 0 3; -10 0 10; -3 0 3] ,Hy = [-3 -10 -3; 0 0 0; 3 10 3]。1. 从(灰度)输入图像I计算单独的水平和垂直边缘图Ix = I ∗ Hx 和 Iy = I ∗ Hy。由于结果值会有正有负,使用其中一种卷积方法和FloatProcessor类型的图像进行此操作。2. 再次以FloatProcessor类型的图像计算局部边缘幅度,对于所有图像位置(u, v),E(u, v) = √(Ix²(u, v) + Iy²(u, v))。3. 将边缘幅度E归一化到[0, 1]。以下ImageProcessor方法可能对此有用:double getMax(),void multiply(double value)。4. 在带有模糊圆形圆盘的测试图像上尝试你的边缘算子并显示结果。定性检查该算子是否真的“各向同性”,即它是否对所有方向的边缘响应相同。

编程实现步骤

本题为编程实现题,具体实现步骤如下:

从灰度输入图像I计算水平和垂直边缘图:

– 将输入图像转换为FloatProcessor类型。

– 使用卷积方法分别用Hx和Hy对图像进行卷积,得到Ix和Iy。

计算局部边缘幅度:

– 对于图像中每个位置(u, v),根据公式E(u, v) = √(Ix²(u, v) + Iy²(u, v))计算边缘幅度,结果仍为FloatProcessor类型。

归一化边缘幅度:

– 使用getMax()方法获取边缘幅度图像的最大值。

– 用1除以最大值得到归一化系数。

– 使用multiply()方法将边缘幅度图像乘以归一化系数,将其归一化到[0, 1]。

测试边缘算子:

– 在带有模糊圆形圆盘的测试图像上应用上述步骤得到边缘结果并显示。

– 定性观察结果,检查算子是否对所有方向的边缘响应相同,判断其是否各向同性。

13、假设二值图像I包含最大直径为5像素的不需要的前景斑点,应在不损坏其余结构的情况下将其移除。设计一个合适的形态学程序,并在适当的测试图像上评估其性能。

图像处理程序设计:形态学收缩与生长操作

可以使用形态学的收缩(shrink)和生长(grow)操作来设计程序,步骤如下:


收缩操作


对图像I进行迭代收缩操作,每次移除前景区域边界的一层像素,直到小的前景斑点(直径最大为5像素)被完全移除。


生长操作


对收缩后的图像进行生长操作,生长的层数与收缩的层数相同,使剩余的较大结构恢复到近似原始形状。

性能评估方法


测试图像选择


可使用不同的测试图像,包括包含不同大小前景斑点和各种结构的图像,来评估该程序的性能。


效果检查


观察处理后的图像,检查小的前景斑点是否被成功移除,以及剩余结构是否未受到明显损坏。

性能判断标准


程序性能良好


如果小的前景斑点被移除且大结构基本保持不变,则说明程序性能良好。


需要优化参数


若大结构变形严重或小斑点仍有残留,则需要调整收缩和生长的参数或操作方式。

14、提出一种使用标准直线绘制命令(两点之间)绘制代数直线L的算法。首先,为代表图像边界的四条直线La, …, Ld创建代数直线,并计算它们与直线L的交点。然后确定哪些(如果有的话)交点在图像的可见部分内。如果L穿过可见图像矩形,则绘制所得的线段(例如,使用ImageJ的ImageProcessor类的drawLine()方法)。

创建代表图像边界的四条直线 $ L_a, dots, L_d $ 的代数直线。

计算直线 $ L_a, dots, L_d $ 与直线 $ L $ 的交点。

确定哪些交点在图像的可见部分内。

若直线 $ L $ 穿过可见图像矩形,使用 ImageJ 的

ImageProcessor

类的

drawLine()

方法绘制所得的线段。

15、以黑塞标准型(HNF)给定的直线无法直接绘制,因为典型的图形环境只能绘制两个指定端点之间的直线。相对于参考点$x_r = (x_r, y_r)$指定的HNF直线$L = ⟨θ, r⟩$,可以通过以下两种方式绘制到图像$I$中:版本1:遍历所有图像点$(u, v)$,若$r = (u – x_r) · cos(θ) + (v – y_r) · sin(θ)$对于位置$(u, v)$成立,则标记像素$I(u, v)$,这种“暴力”方法只会显示那些位置恰好满足直线方程的(少数)直线像素。为获得更“宽容”的绘制方法,将上述等式重新表述为$(u – x_r) · cos(θ) + (v – y_r) · sin(θ) – r = d$。显然,只有当$d$恰好为0时,原等式才成立,若原等式不成立,那么$|d|$等于点$(u, v)$到直线的距离,且$d$本身可能为正或负,这取决于点$(u, v)$位于直线的哪一侧。版本2:定义一个常数$w > 0$,遍历所有图像位置$(u, v)$,每当不等式$|(u – x_r)· cos(θ) + (v – y_r)· sin(θ) – r| ≤ w$对于位置$(u, v)$成立时,标记像素$I(u, v)$。例如,当$w = 1$时,所有直线点都应该显示出来。$w$的几何意义是什么?

w的几何意义是点到直线的最大允许距离,当点到直线的距离小于或等于w时,该点对应的像素会被标记。

16、计算所有检测到的直线的两两交点,并以图形方式展示结果。

要计算所有检测到的直线的两两交点,可使用以下公式。

已知两条直线 $L_1 = langle heta_1, r_1
angle$ 和 $L_2 = langle heta_2, r_2
angle$,交点 $x_{12}=(x_{12}, y_{12})^T$ 需求解线性方程组

{x12⋅cos(θ1)+y12⋅sin(θ1)=r1 x12⋅cos(θ2)+y12⋅sin(θ2)=r2{x12⋅cos⁡(θ1)+y12⋅sin⁡(θ1)=r1 x12⋅cos⁡(θ2)+y12⋅sin⁡(θ2)=r2

其解为

(x12y12)=1sin(θ2−θ1)⋅(r1sin(θ2)−r2sin(θ1)
2cos(θ1)−r1cos(θ2))(x12y12)=1sin⁡(θ2−θ1)⋅(r1sin⁡(θ2)−r2sin⁡(θ1)
2cos⁡(θ1)−r1cos⁡(θ2))

($sin( heta_2 – heta_1)
eq0$)。

若两条直线平行(即 $ heta_1equiv heta_2$),则交点不存在。

完成计算后,可使用绘图工具将交点在图形上进行展示。

17、扩展直线的霍夫变换,使得更新累加器映射时考虑当前像素的边缘幅度。

通常的霍夫变换原始数据是边缘图,将其视为潜在边缘点为1的二值图像。为考虑边缘强度,可在更新累加器单元时,不只是将访问的累加器单元加1,而是加上相应边缘的强度,即:

A(i,j)←A(i,j)+E(u,v)A(i,j)←A(i,j)+E(u,v)

这样强边缘点对累加值的贡献比弱边缘点更大。

18、计算角频率ω = 5的余弦函数f(x) = cos(ωx)在位置x = -3, -2, …, 2, 3处的值。该函数的周期长度是多少?

函数值分别为 cos(-15)、cos(-10)、cos(-5)、cos(0)、cos(5)、cos(10)、cos(15);

周期长度 $ T = frac{2pi}{5} $。

© 版权声明

相关文章

暂无评论

none
暂无评论...