四叉树图像模糊

本文介绍了一种使用四叉树结构对图像进行模糊处理的方法,通过计算方差来识别颜色相近区域,并结合Gauss模糊技术,实现对图像的压缩效果。文章详细阐述了四叉树的构建、方差计算、模糊判断以及Gauss模糊的具体步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

完整代码:https://download.youkuaiyun.com/download/qq_49712456/35325047

一、问题描述

  1. 对图像建立四叉树
  2. 对于输入的图像,四叉树能够输出模糊的结果
  3. 对颜色相近的区域进行模糊

二、实现思路

(一)利用方差

  1. 构造四叉树
  2. 求出分叉区域的平均值和方差
  3. 递归处理,符合模糊条件的将所有值取为平均值

(二)Gauss模糊

  1. 对于每个值,求其周围9个点的加权平均值,并将该点设为均值
  2. 重复上述操作
    注:高斯模糊只能模糊图像,不能进行压缩

三、 代码实现

(一) 四叉树

1. 建立四叉树结构体

包含左上、左下、右上、右下四部分图像的指针
左、右、上、下四个方向的坐标

struct quadTree
{
    quadTree *zs;
    quadTree *zx;
    quadTree *ys;
    quadTree *yx;
    int left;
    int right;
    int up;
    int down;
};

2. 处理四叉树

编写除法函数
除以2余1的,全部退位
避免处理图像时两个区域同时处理同一片坐标点

int division(int a, int b)
{
    if((a + b) % 2 == 1)
        return (a+b-1) / 2;
    else
        return (a+b) / 2;
}

判断这一部分是否满足模糊图像的要求

bool chuli(quadTree *q)
{
    double gave = 0, rave = 0, bave = 0;
    bool re = panduan(q, gave, rave, bave);

若需要继续拆分,则将这一部分拆分成四个部分,分别建立节点

	quadTree *tmp1 = new quadTree;
	tmp1->up = q->up;
	tmp1->down = division(q->down , q->up);
	tmp1->left = q->left;
	tmp1->right = division(q->right , q->left);
	tmp1->zs = NULL;
	tmp1->zx = NULL;
	tmp1->ys = NULL;
	tmp1->yx = NULL;
	q->zs = tmp1;

对于左上部分结点,左、上坐标不变,右、下坐标为求和后取半
其余三个部分同理

	quadTree *tmp2 = new quadTree;
	tmp2->up = division(q->up , q->down);
	tmp2->down = q->down;
	tmp2->left = q->left;
	tmp2->right = division(q->right , q->left);
	tmp2->zs = NULL;
	tmp2->zx = NULL;
	tmp2->ys = NULL;
	tmp2->yx = NULL;
	q->zx = tmp2;
	
	quadTree *tmp3 = new quadTree;
	tmp3->up = q->up;
	tmp3->down = division(q->down , q->up);
	tmp3->left = division(q->left , q->right);
	tmp3->right = q->right;
	tmp3->zs = NULL;
	tmp3->zx = NULL;
	tmp3->ys = NULL;
	tmp3->yx = NULL;
	q->ys = tmp3;
	
	quadTree *tmp4 = new quadTree;
	tmp4->up = division(q->up , q->down);
	tmp4->down = q->down;
	tmp4->left = division(q->left , q->right);
	tmp4->right = q->right;
	tmp4->zs = NULL;
	tmp4->zx = NULL;
	tmp4->ys = NULL;
	tmp4->yx = NULL;
	q->yx = tmp4;

返回false,表示需要继续递归

	return false;

若满足条件
则将这一部分所有结点都更改为平均值
并返回true,表示结束递归

else
{
    for(int i = q->left; i < q->right; i++)
        for(int j = q->down; j < q->up; j++)
    {
        colors[j][i].b = bave;
        colors[j][i].g = gave;
        colors[j][i].r = rave;
    }
    return true;
}

3. 四叉树递归

判断是否需要继续递归
若已经达到模糊条件,则退出递归
否则,分别递归四个部分结点

void digui(quadTree *r)
{
    bool re = chuli(r);
    if(re == true)
        return;
    digui(r->yx);
    digui(r->zs);
    digui(r->ys);
    digui(r->zx);
}

创建根结点,并递归根结点

void chaifen(int height)
{
    quadTree *root = new quadTree;
    root->down = 0;
    root->left = 0;
    root->right = height;
    root->up = height;
    root->ys = NULL;
    root->zs = NULL;
    root->yx = NULL;
    root->zx = NULL;

    digui(root);
}

(二) 图像处理(方差)

1. 求平均值

将该区域图像内的每一个坐标点的颜色值相加

    for(int i=q->left; i<q->right; i++)
        for(int j=q->down; j<q->up; j++)
        {
            rave += double(colors[j][i].r);
            gave += double(colors[j][i].g);
            bave += double(colors[j][i].b);
        }

除以坐标点个数,即面积

    int square = (q->up - q->down) * (q->right - q->left);
    rave /= square;
    gave /= square;
    bave /= square;

2. 求方差

方法与求平均值相同

for(int i=q->left; i<q->right; i++)
    for(int j=q->down; j<q->up; j++)
    {
        Dr += (rave - double(colors[j][i].r)) * (rave - double(colors[j][i].r));
        Dg += (gave - double(colors[j][i].g)) * (gave - double(colors[j][i].g));
        Db += (bave - double(colors[j][i].b)) * (bave - double(colors[j][i].b));
    }
Dr /= square;
Dg /= square;
Db /= square;

3. 判断

若方差大于标准值,则继续拆分该区域
否则,将该区域所有的点的颜色设为平均值

bool panduan(quadTree *q, double &gave, double &rave, double &bave)
{
    double Dr = 0, Dg = 0, Db = 0;
    D(q, Dr, Dg, Db, gave, rave, bave);

    if(Dr > standard || Dg > standard || Db > standard)
        return true;
    return false;
}

(三) 图像处理(Gauss模糊)

1. 单次模糊

高斯模糊的原理:
中间点取周围点的加权平均值,取点个数由取点半径radius决定
周围点的权重由正态分布函数分配,这里取值如下:

double quanzhong[3][3] = {{0.0453542, 0.0566406, 0.0453542}, {0.0566406, 0.0707355, 0.0566406}, {0.0453542, 0.0566406, 0.0453542}};

为了将所有点的权值和为1,每个点都除以0.4787147
遍历整张图象,对每个点都进行处理

for(int i=1; i<width-1; i++)
    for(int j=1; j<width-1; j++)
    {
        double gave = 0, rave = 0, bave = 0;
        for(int k=-1; k<=radias; k++)
            for(int l=-1; l<=radias; l++)
            {
                rave += double(colors[j+k][i+l].r) * quanzhong[k][l];
                gave += double(colors[j+k][i+l].g) * quanzhong[k][l];
                bave += double(colors[j+k][i+l].b) * quanzhong[k][l];
            }
        colors[j][i].r = rave;
        colors[j][i].g = rave;
        colors[j][i].b = rave;
    }

2. 多次调用

自定义调用次数

void diaoyong(int width)
{
    for(int i=1; i<cishu; i++)
    {
        Guass(width);
    }
}

(四) ppm格式转换

为了方便查看结果,用python将ppm格式图片转化为jpg格式

from PIL import Image
 
img = Image.open("C:\\Users\\15313\\Desktop\\homework\\tree\\b.ppm")
img.save("C:\\Users\\15313\\Desktop\\homework\\tree\\b.jpg")
img.show()

四.实验结果

(一) 利用方差判断

  1. 标准值取100

  2. 标准值取500

(二) Gauss模糊

(Gauss模糊只能达到模糊的目的,不能实现压缩)
半径radius = 1,调用次数cishu = 20

五.小结感悟

(一) 失误

  1. 在chuli函数中,不能用tmp构造4个分叉
    因为tmp是指针,传的是地址,会导致4个分叉对应同一个tmp
  2. printImage函数中FILE *f = fopen(fileName, “wb”);
    必须要用”wb”,不能使用”w”,否则会有上次的文件残留

(二) 收获

  1. 对图片压缩的方法有了一个初步认知,可能对以后的学习研究有帮助
    了解一些模糊图像的原理和方法
  2. 运用四叉树后,有助于对树结构的学习
    在使用递归函数时经常出现意料之外的bug,解决完这些bug让我对递归的理解更进一步
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ETO降临派

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值