一、效果图

二、demo源码地址(除了磨皮还有一些基本的滤镜)

如果你觉得有用的话,期待你的小星星
实战应用项目:
github :https://github.com/dependon/simple-image-filter //纯qt图像处理项目

三、接口代码

img参数是原始图像,返回的是处理后的图像

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <math.h>
#include <QVector>
#include <QColor>
#include <QImage>
#include <QPainter>
QImage QImageAPI::QImageD_RunBEEPSHorizontalVertical(const QImage &img, double spatialDecay, double photometricStandardDeviation)
{ QImage imgCopy = QImage(img); double c = -0.5 / (photometricStandardDeviation * photometricStandardDeviation); //-1/2 *光度标准偏差的平方
double mu = spatialDecay / (2 - spatialDecay); double *exptable = new double[256];
double *g_table = new double[256];
for (int i = 0; i <= 255; i++) {
exptable[i] = (1 - spatialDecay) * exp(c * i * i);
g_table[i] = mu * i;
}
int width = img.width();
int height = img.height();
int length = width * height;
double *data2Red = new double[length];
double *data2Green = new double[length];
double *data2Blue = new double[length]; int i = 0; for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
QRgb rgb = imgCopy.pixel(x, y);
data2Red[i] = qRed(rgb);
data2Green[i] = qGreen(rgb);
data2Blue[i] = qBlue(rgb);
i++;
}
} double *gRed = new double[length];
double *pRed = new double[length];
double *rRed = new double[length]; double *gGreen = new double[length];
double *pGreen = new double[length];
double *rGreen = new double[length]; double *gBlue = new double[length];
double *pBlue = new double[length];
double *rBlue = new double[length];
memcpy(pRed, data2Red, sizeof(double) * length);
memcpy(rRed, data2Red, sizeof(double) * length); memcpy(pGreen, data2Green, sizeof(double) * length);
memcpy(rGreen, data2Green, sizeof(double) * length); memcpy(pBlue, data2Blue, sizeof(double) * length);
memcpy(rBlue, data2Blue, sizeof(double) * length); double rho0 = 1.0 / (2 - spatialDecay);
for (int k2 = 0; k2 < height; ++k2) {
int startIndex = k2 * width;
double mu = 0.0;
for (int k = startIndex + 1, K = startIndex + width; k < K; ++k) {
int div0Red = fabs(pRed[k] - pRed[k - 1]);
mu = exptable[div0Red];
pRed[k] = pRed[k - 1] * mu + pRed[k] * (1.0 - mu);//公式1 int div0Green = fabs(pGreen[k] - pGreen[k - 1]);
mu = exptable[div0Green];
pGreen[k] = pGreen[k - 1] * mu + pGreen[k] * (1.0 - mu);//公式1 int div0Blue = fabs(pBlue[k] - pBlue[k - 1]);
mu = exptable[div0Blue];
pBlue[k] = pBlue[k - 1] * mu + pBlue[k] * (1.0 - mu);//公式1 } for (int k = startIndex + width - 2; startIndex <= k; --k) {
int div0Red = fabs(rRed[k] - rRed[k + 1]);
double mu = exptable[div0Red];
rRed[k] = rRed[k + 1] * mu + rRed[k] * (1.0 - mu);//公式3 int div0Green = fabs(rGreen[k] - rGreen[k + 1]);
mu = exptable[div0Green];
rGreen[k] = rGreen[k + 1] * mu + rGreen[k] * (1.0 - mu);//公式3 int div0Blue = fabs(rBlue[k] - rBlue[k + 1]);
mu = exptable[div0Blue];
rBlue[k] = rBlue[k + 1] * mu + rBlue[k] * (1.0 - mu);//公式3
}
for (int k = startIndex, K = startIndex + width; k < K; k++) {
rRed[k] = (rRed[k] + pRed[k]) * rho0 - g_table[(int)data2Red[k]];
rGreen[k] = (rGreen[k] + pGreen[k]) * rho0 - g_table[(int)data2Green[k]];
rBlue[k] = (rBlue[k] + pBlue[k]) * rho0 - g_table[(int)data2Blue[k]];
}
} int m = 0;
for (int k2 = 0; k2 < height; k2++) {
int n = k2;
for (int k1 = 0; k1 < width; k1++) {
gRed[n] = rRed[m];
gGreen[n] = rGreen[m];
gBlue[n] = rBlue[m];
m++;
n += height;
}
} memcpy(pRed, gRed, sizeof(double) * height * width);
memcpy(rRed, gRed, sizeof(double) * height * width); memcpy(pGreen, gGreen, sizeof(double) * height * width);
memcpy(rGreen, gGreen, sizeof(double) * height * width); memcpy(pBlue, gBlue, sizeof(double) * height * width);
memcpy(rBlue, gBlue, sizeof(double) * height * width); for (int k1 = 0; k1 < width; ++k1) {
int startIndex = k1 * height;
double mu = 0.0;
for (int k = startIndex + 1, K = startIndex + height; k < K; ++k) {
int div0Red = fabs(pRed[k] - pRed[k - 1]);
mu = exptable[div0Red];
pRed[k] = pRed[k - 1] * mu + pRed[k] * (1.0 - mu); int div0Green = fabs(pGreen[k] - pGreen[k - 1]);
mu = exptable[div0Green];
pGreen[k] = pGreen[k - 1] * mu + pGreen[k] * (1.0 - mu); int div0Blue = fabs(pBlue[k] - pBlue[k - 1]);
mu = exptable[div0Blue];
pBlue[k] = pBlue[k - 1] * mu + pBlue[k] * (1.0 - mu);
}
for (int k = startIndex + height - 2; startIndex <= k; --k) {
int div0Red = fabs(rRed[k] - rRed[k + 1]);
mu = exptable[div0Red];
rRed[k] = rRed[k + 1] * mu + rRed[k] * (1.0 - mu); int div0Green = fabs(rGreen[k] - rGreen[k + 1]);
mu = exptable[div0Green];
rGreen[k] = rGreen[k + 1] * mu + rGreen[k] * (1.0 - mu); int div0Blue = fabs(rBlue[k] - rBlue[k + 1]);
mu = exptable[div0Blue];
rBlue[k] = rBlue[k + 1] * mu + rBlue[k] * (1.0 - mu);
}
} double init_gain_mu = spatialDecay / (2 - spatialDecay);
for (int k = 0; k < length; ++k) {
rRed[k] = (rRed[k] + pRed[k]) * rho0 - gRed[k] * init_gain_mu; rGreen[k] = (rGreen[k] + pGreen[k]) * rho0 - gGreen[k] * init_gain_mu; rBlue[k] = (rBlue[k] + pBlue[k]) * rho0 - gBlue[k] * init_gain_mu; } m = 0;
for (int k1 = 0; k1 < width; ++k1) {
int n = k1;
for (int k2 = 0; k2 < height; ++k2) { data2Red[n] = rRed[m];
data2Green[n] = rGreen[m];
data2Blue[n] = rBlue[m];
imgCopy.setPixel(k1, k2, qRgb(data2Red[n], data2Green[n], data2Blue[n]));
m++;
n += width;
}
}
delete []data2Red;
data2Red = nullptr;
delete []data2Green ;
data2Green = nullptr;
delete []data2Blue;
data2Blue = nullptr; delete []pRed;
pRed = nullptr;
delete []rRed;
rRed = nullptr;
delete []gRed;
gRed = nullptr; delete []pGreen;
pGreen = nullptr;
delete []rGreen;
rGreen = nullptr;
delete []gGreen;
gGreen = nullptr; delete []pBlue;
pBlue = nullptr;
delete []rBlue;
rBlue = nullptr;
delete []gBlue;
gBlue = nullptr; delete []exptable;
exptable = nullptr;
delete []g_table;
g_table = nullptr; return imgCopy;
}

四、原始代码(上面接口是根据原始代码修改的)

//原始代码
static void RunBEEPSVerticalHorizontal(double *data,int width,int height,double spatialDecay,double *exp_table,double *g_table)
{
int length0=height*width;
double* g= new double[length0];
int m = 0;
for (int k2 = 0;k2<height;++k2)
{
int n = k2;
for (int k1 = 0;k1<width;++k1)
{
g[n]=data[m++];
n += height;
}
}
double*p = new double[length0];
double*r = new double[length0];
memcpy(p, g, sizeof(double) * length0);
memcpy(r, g, sizeof(double) * length0);
for (int k1 = 0;k1<width; ++k1)
{
int startIndex=k1 * height;
double mu = 0.0;
for (int k=startIndex+1,K =startIndex+height;k<K;++k)
{
int div0=fabs(p[k]-p[k-1]);
mu =exp_table[div0];
p[k] = p[k - 1] * mu + p[k] * (1.0 - mu);//文献中的公式1,这里做了一下修改,效果影响不大
}
for (int k =startIndex+height-2;startIndex <= k;--k)
{
int div0=fabs(r[k]-r[k+1]);
mu =exp_table[div0];
r[k] = r[k+1] * mu + r[k] * (1.0-mu) ;//文献公式3
}
}
double rho0=1.0/(2-spatialDecay);
for (int k = 0;k <length0;++k)
{
r[k]= (r[k]+p[k])*rho0-g_table[(int)g[k]];
}
m = 0;
for (int k1=0;k1<width;++k1)
{
int n = k1;
for (int k2 =0;k2<height;++k2)
{
data[n] = r[m++];
n += width;
}
} memcpy(p,data, sizeof(double) * length0);
memcpy(r,data, sizeof(double) * length0);
for (int k2 = 0; k2<height;++k2)
{
int startIndex=k2 * width;
double mu = 0.0;
for (int k=startIndex+1, K=startIndex+width;k<K;++k)
{
int div0=fabs(p[k]-p[k-1]);
mu =exp_table[div0];
p[k] = p[k - 1] * mu + p[k] * (1.0 - mu);
}
for (int k=startIndex+width-2;startIndex<=k;--k)
{
int div0=fabs(r[k]-r[k+1]);
mu =exp_table[div0];
r[k] = r[k + 1] * mu + r[k] * (1.0 - mu) ;
}
} double init_gain_mu=spatialDecay/(2-spatialDecay);
for (int k = 0; k <length0; k++)
{
data[k]=(p[k]+r[k])*rho0-data[k]*init_gain_mu;//文献中的公式5
}
delete[] p;
delete[] r;
delete[] g;
}

四、公式原理

The first recursion is progressive. Letting x[k] be the current sample of an input sequence x at location k ∈ Z,were cursively compute the elements of an auxiliary sequence ϕ as:
where:

The second recursion is regressive and very similar to thefirst one, except for a reversal of the order in which the indices are traversed. We recursively compute a second auxiliary sequence φ as:

where:

We complete our algorithm by merging the resulting progressive sequence ϕ and regressive sequence φ to produce the samples of the output sequence y as:
在这里我们主要使用到了上面的公式1和公式3,并在关键代码使用里面有所标注。

联系我

liuminghang0821@qq.com
有问必答,期待点赞,github星星

Qt图像处理技术一:对QImage图片美颜,使用双指数滤波的更多相关文章

  1. 搭建Android+QT+OpenCV环境,实现“单色图片着色”效果

               OpenCV是我们大家非常熟悉的图像处理开源类库:在其新版本将原本在Contrib分库中的DNN模块融合到了主库中,并且更新了相应文档.这样我们就能够非常方便地利用OpenCV实 ...

  2. HTML5图形图像处理技术研究

    摘要:图形图像处理平台大部分是传统的C/S架构的桌面应用程序,维护困难,共享性差,而B/S架构的Web程序具有易维护.易共享的优点.本文研究了基于HTML5的Web图形图像处理技术,用HTML5实现了 ...

  3. GDI+图形图像处理技术中Pen和Brush的简单使用和简单图形的绘制(C#)

    1.Graphics Graphics对象是GDI+绘图表面,因此在Windows窗体应用程序中要使用GDI+创建绘图,必须要先创建Graphics.在给窗体注册一个Paint事件后,Graphics ...

  4. 数字图像处理技术在TWaver可视化中的应用

    数字图像处理(Digital Image Processing)又称为计算机图像处理,它是指将图像信号转换成数字信号并利用计算机对其进行处理的过程.常用的图像处理方法有图像增强.复原.编码.压缩等,数 ...

  5. php图形图像处理技术

    图形图像处理技术,gd库的强大支持,PHP的图像可以是PHP的强项,PHP图形化类库,jpgraph是一款非常好用的强大的图形处理工具. 在PHP中加载GD库 gd官方网址下载: http://www ...

  6. FPGA与数字图像处理技术

    数字图像处理方法的重要性源于两个主要应用领域: 改善图像信息以便解释. 为存储.传输和表示而对图像数据进行处理,以便于机器自动理解. 图像处理(image processing): 用计算机对图像进行 ...

  7. Qt 打开安卓相冊选择图片并获取图片的本地路径

    Qt 打开安卓相冊选择图片并获取图片的本地路径 过程例如以下: 通过 Intent 打开安卓的系统相冊. 推荐使用 QAndroidJniObject::getStaticObjectField 获取 ...

  8. Qt开发技术:QCharts(三)QCharts样条曲线图介绍、Demo以及代码详解

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  9. Qt开发技术:图形视图框架(二)场景QGraphicsScene、QGraphicsItem与QGraphicsView详解

    前话   Qt的图形视图框架,最核心的三个类为:QGraphicsScene.QGraphicsItem与QGraphicsView.   基于图形框架的高级白板软件Demo QGraphicsSce ...

  10. Qt QPixmap QImage 图片等比例缩放到指定大小

    QPixmap pixmap(path); //pixmap=QPixmap::fromImage(imgShow); pixmap = pixmap.scaled(, , Qt::KeepAspec ...

随机推荐

  1. 目标检测 | Farthest Point Sampling 及其 CUDA 实现

    Farthest Point Sampling 及其 CUDA 实现 目录 Farthest Point Sampling 及其 CUDA 实现 概述 均匀随机采样 Farthest Point Sa ...

  2. 探秘Transformer之(8)--- 位置编码

    探秘Transformer之(8)--- 位置编码 0x00 概述 位置编码(Positional Embedding)是一种用于处理序列数据的技术,被用来表示输入序列中的单词位置.在Transfor ...

  3. Python装饰器:套层壳我变得更强了!

    Python装饰器:套层壳我变得更强了 Python装饰器:套层壳我变得更强了 关于作用域和闭包可以聊点什么? 什么是作用域 什么是闭包 装饰器:套层壳我变得更强了 参考资料 昨天阅读了<Pyt ...

  4. Redmine 中,如何新增一个字段名,比如"模块名称":

    why: 用于编写测试报告时能够直接根据模块名称进行统计,不对excel 表格进行自定义拆分-----规范性 登录到 Redmine 平台,并进入你的项目页面. 在项目页面上方的导航栏中,点击 &qu ...

  5. 【BUG】鸿蒙模拟器虚拟化问题的解决方案

    创建记事本文档.txt,键入以下代码: pushd "%~dp0" dir /b %SystemRoot%\servicing\Packages\*Hyper-V*.mum > ...

  6. 服务器Go程序意外停止自动重启

    判断进程是否挂掉 ps -ef | grep ./blog |wc -l 如果输出为1,说明进程挂掉了 如果输出为2,说明进程正常运行 编辑脚本来检测和完成重启 vim restart.sh 逻辑代码 ...

  7. Windows下安装使用OpenLDAP

    LDAP:(轻量级目录访问协议,Lightweight Directory Access Protocol)它是基于 X.500标准的,但是简单多了并且可以根据需要定制.与X.500不同,LDAP支持 ...

  8. nginx同时使用(http)80和(https)443端口详解

    server { listen 443 ssl; #监听https 443时需加ssl server_name ; #你的域名 ssl on; ssl_certificate ; #证书路径 ssl_ ...

  9. [每日算法 - 华为机试] leetcode20 :有效的括号 「栈」

    入口 力扣https://leetcode.cn/problems/valid-parentheses/submissions/ 题目描述 给定一个只包括 '(',')','{','}','[','] ...

  10. 我对TamperMonkey的不满-更新中

    我认为我的电脑上的TamperMonkey插件的值得考虑的不足: 没有提供一个把脚本最小化的功能 不能编辑热键 脚本icon不能使用svg 没有提供一种很好的能够区分别人的脚本和自己的脚本的方式,自己 ...