对于想了解PythonOpenCV图片模糊操作blur与medianBlur的读者,本文将提供新的信息,我们将详细介绍pythonopencv图片处理,并且为您提供关于36篇博文带你学完opencv:
对于想了解Python OpenCV 图片模糊操作 blur 与 medianBlur的读者,本文将提供新的信息,我们将详细介绍python opencv图片处理,并且为您提供关于36 篇博文带你学完 opencv :python+opencv 进阶版学习笔记目录、Android高斯模糊、高斯平滑(Gaussian Blur)【1】、Android高斯模糊、高斯平滑(Gaussian Blur)【2】、AR opencv-python | cv2.error: OpenCV(4.5.1) batch_distance.cpp:275: error: (-215:Assertion failed)的有价值信息。
本文目录一览:- Python OpenCV 图片模糊操作 blur 与 medianBlur(python opencv图片处理)
- 36 篇博文带你学完 opencv :python+opencv 进阶版学习笔记目录
- Android高斯模糊、高斯平滑(Gaussian Blur)【1】
- Android高斯模糊、高斯平滑(Gaussian Blur)【2】
- AR opencv-python | cv2.error: OpenCV(4.5.1) batch_distance.cpp:275: error: (-215:Assertion failed)
Python OpenCV 图片模糊操作 blur 与 medianBlur(python opencv图片处理)
Python OpenCV 365 天学习计划,与橡皮擦一起进入图像领域吧。
Python OpenCV
-
- 基础知识铺垫
- 函数原型介绍
-
- 均值模糊
- 中值模糊
- 2D 卷积(图像滤波),自定义模糊
- 橡皮擦的小节
- 推荐阅读
基础知识铺垫
Python OpenCV 中模糊操作的原理是:
基于离散卷积、定义好每个卷积核、不同卷积核得到不同的卷积效果、模糊是卷积的一种表象。橡皮擦表示没看懂,先在脑子中有个大概印象就行,毕竟才学习 20 多天。
本篇博客要学习的模糊有
- 均值模糊:一般用来处理图像的随机噪声;
- 中值模糊:一般用来处理图像的椒盐噪声;
- 自定义模糊:对图像进行增强,锐化等操作。
函数原型介绍
均值模糊
概念:
均值滤波是典型的线性滤波算法,它是指在图像上对目标像素给一个模板,该模板包括了其周围的临近像素(以目标像素为中心的周围 8 个像素,构成一个滤波模板,即去掉目标像素本身),再用模板中的全体像素的平均值来代替原来像素值。
哇哦,没看懂,直接看一下原型吧,先用起来,在复盘理论。
cv2.blur(src, ksize[, dst[, anchor[, borderType]]]) -> dst
参数说明:
- src:待处理图像,熟悉参数;
- ksize:表示模糊内核大小。比如(5,5)表示生成的模糊内核是一个 5*5 的矩阵;
- dst:表示输出与 src 相同大小和类型的图像;
- anchor:可选参数
- borderType:可选参数
测试代码如下:
import cv2 as cv
import numpy as np
def blur_demo(src):
dst = cv.blur(src, (5, 5))
cv.imshow("blur_demo", dst)
if __name__ == "__main__":
src = cv.imread("./1.jpg")
blur_demo(src)
cv.waitKey()
cv.destroyAllWindows()
中值模糊
概念(读一读就行了):
中值滤波法是一种非线性平滑技术,它将每一像素点的灰度值设置为该点某邻域窗口内的所有像素点灰度值的中值。
函数原型如下:
cv2.medianBlur(src, ksize[, dst]) -> dst
参数说明:
- src:待处理的输入图像;
- ksize:参数表示滤波窗口尺寸,必须是奇数并且大于 1。比如这里是 5,中值滤波器就会使用 5×5 的范围来计算,即对像素的中心值及其 5×5 邻域组成了一个数值集,对其进行处理计算,当前像素被其中值替换掉;
- dst:参数表示输出与 src 相同大小和类型的图像。
中值模糊一般用在存在一些躁声点图像,例如白噪声,可以去除。
首先通过下述代码制造一张椒盐图片。
import numpy as np
import random
import cv2
def sp_noise(image, prob):
output = np.zeros(image.shape, np.uint8)
thres = 1 - prob
for i in range(image.shape[0]):
for j in range(image.shape[1]):
rdn = random.random()
if rdn < prob:
output[i][j] = 0
elif rdn > thres:
output[i][j] = 255
else:
output[i][j] = image[i][j]
return output
img = cv2.imread("./1.jpg")
# 添加椒盐噪声,噪声比例 0.02
out = sp_noise(img, prob=0.02)
cv2.imshow("img", out)
cv2.waitKey()
对上述代码生成的图片进行中值模糊操作。
# 中值模糊 ,去椒盐噪声
def median_blur_demo(src):
dst = cv.medianBlur(src, 3)
cv.imshow("dst", dst)
2D 卷积(图像滤波),自定义模糊
概念:
图像作为一个一维信号,也可以通过多种低通过滤器(low-pass filters, LPF)和高通过滤器(high-pass filters, HPF)来过滤。低通过滤器可以去除噪声,或者模糊图像。高通过滤器可以帮助在一个图像中找出边界。
函数原型为:
cv2.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]]) -> dst
参数说明:
- src:待处理的输入图像;
- ddepth:表示目标图像深度,输入值为-1 时,目标图像和原图像深度保持一致;
- kernel::卷积核(或者是相关核),一个单通道浮点型矩阵。修改 kernel 矩阵即可实现不同的模糊;
- anchor:可选参数,内核的锚点,指示内核中过滤点的相对位置;锚应位于内核中;默认值(-1,-1)表示锚位于内核中心;
- detal :可选参数,在将它们存储在 dst 中之前,将可选值添加到已过滤的像素中。类似于偏置;
- borderType:可选参数,像素外推法
测试代码如下:
# 模糊操作
def filter2D_demo(src):
# 除以 25 是防止溢出
kernel = np.ones([5,5],np.float32)/25
dst = cv.filter2D(src,-1,kernel=kernel)
cv.imshow("dst",dst)
运行效果:
使用 filter2D
函数,实现锐化。
def filter2D_demo(src):
# 当kernel总和为 1 时:增强锐化
# 当kernel总和为 0 时:边缘梯度
kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]], np.float32)
dst = cv.filter2D(src, -1, kernel=kernel)
cv.imshow("dst", dst)
注意上述代码中 kernel
对应的数组中,各个值都为奇数,总和要等于 1,才是锐化。
橡皮擦的小节
本系列博客为学习之旅,部分概念在没有学到,或者必须彻底掌握前,不做扩展学习。保持每天 1 个小时的学习时间即可。
1 个小时又过去了,对 Python OpenCV 相关的知识点,你掌握了吗?
做为初学者,还有很多地方学习的不深入,希望你与我一起坚持下去。
推荐阅读
空闲之余,可以订阅橡皮擦的爬虫百例课程学习爬虫知识。
想学 Python 爬虫,可以订阅橡皮擦专栏哦~
点击发现惊喜
今天是持续写作的第 60 / 100 天。
如果你有想要交流的想法、技术,欢迎在评论区留言。
如果你想跟博主建立亲密关系,可以关注博主,或者关注博主公众号 “
非本科程序员
”,了解一个非本科程序员是如何成长的。
博主 ID:梦想橡皮擦
,希望大家点赞、评论、收藏
本文同步分享在 博客“梦想橡皮擦”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
36 篇博文带你学完 opencv :python+opencv 进阶版学习笔记目录
基础版学习笔记传送门
36 篇博文带你学完 opencv :python3+opencv 学习笔记汇总目录(基础版)
进阶版笔记
项目 |
---|
opencv 进阶学习笔记 1: 调用摄像头用法大全(打开摄像头,打开摄像头并实时不断截屏,读取视频并截图) |
opencv 进阶学习笔记 2:numpy 操作图像,色彩空间,查找指定颜色范围,通道分离与合并 |
opencv 进阶学习笔记 3:像素运算和图像亮度对比度调节 |
opencv 进阶学习笔记 4:ROI 和泛洪扩充 |
opencv 进阶学习笔记 5:图像模糊操作,图像锐化,边缘保留滤波 EPF(图像滤镜) |
opencv 进阶学习笔记 6:使用鼠标在图像上绘制矩形框或者多边形框 |
opencv 进阶学习笔记 7:直方图,直方图均衡化,直方图比较,直方图反向投影 |
opencv 进阶学习笔记 8:模板匹配 |
opencv 进阶学习 9:图像阈值大全,图像二值化,超大图像二值化 |
opencv 进阶学习笔记 10:图像金字塔和图像梯度 |
opencv 进阶学习笔记 11:cannny 边缘检测,直线检测,圆检测 |
opencv 进阶学习笔记 12:轮廓发现和对象测量 |
opencv 进阶学习笔记 13:图像形态学操作大全(膨胀,腐蚀,开闭,黑帽,顶帽,梯度)python 版 |
opencv 进阶学习笔记 14:分水岭算法 实现图像分割 |
OpenCV 告一段落,接下来,该实战啦。
计算机视觉三大任务,分类,监测,分割。
意见其他一些任务…
图像生成,OCR…
电气专业的计算机萌新,写博文不容易,如果你觉得本文对你有用,请点个赞支持下,谢谢。
Android高斯模糊、高斯平滑(Gaussian Blur)【1】
Android高斯模糊、高斯平滑(Gaussian Blur)【1】
Android高斯模糊、高斯平滑(Gaussian Blur),图形图像处理的一种效果,经过高斯模糊处理后的图片有一种“毛玻璃”的效果。
Android上的高斯模糊实现算法不少,现在结合一个流传甚广的算法(注意,此算法的性能有待进一步提高),写一个高斯模糊的例子,实现“毛玻璃”的图像效果。
写一个布局:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/blurButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:text="高斯模糊 力度:0" />
<Button
android:id="@+id/restButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="重置" />
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/pic" />
</FrameLayout>
测试的主Activity MainActivity.java:
package zhangphil.blur;
import android.widget.Button;
import android.widget.ImageView;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends Activity {
private int radius = 0;
private Button blurButton;
private ImageView image;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
image = (ImageView) findViewById(R.id.imageView);
blurButton = (Button) findViewById(R.id.blurButton);
blurButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
doMyBlur();
}
});
Button restButton = (Button) findViewById(R.id.restButton);
restButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
rest();
}
});
}
// 每次都加深力度10
private void doMyBlur() {
radius = radius + 10;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pic);
Bitmap bmp = FastBlur.doBlur(bitmap, radius, false);
image.setImageBitmap(bmp);
blurButton.setText("高斯模糊 力度:" + radius);
}
// 重置为原始状态
private void rest() {
radius = 0;
image.setImageResource(R.drawable.pic);
blurButton.setText("高斯模糊 力度:" + radius);
}
}
核心的工具类FastBlur.java:
package zhangphil.blur;
import android.graphics.Bitmap;
import android.util.Log;
public class FastBlur {
public Bitmap fastblur(Bitmap sentBitmap, int radius) {
// Stack Blur v1.0 from
// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
//
// Java Author: Mario Klingemann <mario at quasimondo.com>
// http://incubator.quasimondo.com
// created Feburary 29, 2004
// Android port : Yahel Bouaziz <yahel at kayenko.com>
// http://www.kayenko.com
// ported april 5th, 2012
// This is a compromise between Gaussian Blur and Box blur
// It creates much better looking blurs than Box Blur, but is
// 7x faster than my Gaussian Blur implementation.
//
// I called it Stack Blur because this describes best how this
// filter works internally: it creates a kind of moving stack
// of colors whilst scanning through the image. Thereby it
// just has to add one new block of color to the right side
// of the stack and remove the leftmost color. The remaining
// colors on the topmost layer of the stack are either added on
// or reduced by one, depending on if they are on the right or
// on the left side of the stack.
//
// If you are using this algorithm in your code please add
// the following line:
//
// Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
if (radius < 1) {
return (null);
}
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int[] pix = new int[w * h];
Log.e("pix", w + " " + h + " " + pix.length);
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
int wm = w - 1;
int hm = h - 1;
int wh = w * h;
int div = radius + radius + 1;
int r[] = new int[wh];
int g[] = new int[wh];
int b[] = new int[wh];
int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
int vmin[] = new int[Math.max(w, h)];
int divsum = (div + 1) >> 1;
divsum *= divsum;
int dv[] = new int[256 * divsum];
for (i = 0; i < 256 * divsum; i++) {
dv[i] = (i / divsum);
}
yw = yi = 0;
int[][] stack = new int[div][3];
int stackpointer;
int stackstart;
int[] sir;
int rbs;
int r1 = radius + 1;
int routsum, goutsum, boutsum;
int rinsum, ginsum, binsum;
for (y = 0; y < h; y++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
for (i = -radius; i <= radius; i++) {
p = pix[yi + Math.min(wm, Math.max(i, 0))];
sir = stack[i + radius];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rbs = r1 - Math.abs(i);
rsum += sir[0] * rbs;
gsum += sir[1] * rbs;
bsum += sir[2] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
}
stackpointer = radius;
for (x = 0; x < w; x++) {
r[yi] = dv[rsum];
g[yi] = dv[gsum];
b[yi] = dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (y == 0) {
vmin[x] = Math.min(x + radius + 1, wm);
}
p = pix[yw + vmin[x]];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[(stackpointer) % div];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi++;
}
yw += w;
}
for (x = 0; x < w; x++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
yp = -radius * w;
for (i = -radius; i <= radius; i++) {
yi = Math.max(0, yp) + x;
sir = stack[i + radius];
sir[0] = r[yi];
sir[1] = g[yi];
sir[2] = b[yi];
rbs = r1 - Math.abs(i);
rsum += r[yi] * rbs;
gsum += g[yi] * rbs;
bsum += b[yi] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
if (i < hm) {
yp += w;
}
}
yi = x;
stackpointer = radius;
for (y = 0; y < h; y++) {
// Preserve alpha channel: ( 0xff000000 & pix[yi] )
pix[yi] = ( 0xff000000 & pix[yi] ) | ( dv[rsum] << 16 ) | ( dv[gsum] << 8 ) | dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (x == 0) {
vmin[y] = Math.min(y + r1, hm) * w;
}
p = x + vmin[y];
sir[0] = r[p];
sir[1] = g[p];
sir[2] = b[p];
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[stackpointer];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi += w;
}
}
Log.e("pix", w + " " + h + " " + pix.length);
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
return (bitmap);
}
public static Bitmap doBlur(Bitmap sentBitmap, int radius,
boolean canReuseInBitmap) {
// Stack Blur v1.0 from
// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
//
// Java Author: Mario Klingemann <mario at quasimondo.com>
// http://incubator.quasimondo.com
// created Feburary 29, 2004
// Android port : Yahel Bouaziz <yahel at kayenko.com>
// http://www.kayenko.com
// ported april 5th, 2012
// This is a compromise between Gaussian Blur and Box blur
// It creates much better looking blurs than Box Blur, but is
// 7x faster than my Gaussian Blur implementation.
//
// I called it Stack Blur because this describes best how this
// filter works internally: it creates a kind of moving stack
// of colors whilst scanning through the image. Thereby it
// just has to add one new block of color to the right side
// of the stack and remove the leftmost color. The remaining
// colors on the topmost layer of the stack are either added on
// or reduced by one, depending on if they are on the right or
// on the left side of the stack.
//
// If you are using this algorithm in your code please add
// the following line:
//
// Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
Bitmap bitmap;
if (canReuseInBitmap) {
bitmap = sentBitmap;
} else {
bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
}
if (radius < 1) {
return (null);
}
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int[] pix = new int[w * h];
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
int wm = w - 1;
int hm = h - 1;
int wh = w * h;
int div = radius + radius + 1;
int r[] = new int[wh];
int g[] = new int[wh];
int b[] = new int[wh];
int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
int vmin[] = new int[Math.max(w, h)];
int divsum = (div + 1) >> 1;
divsum *= divsum;
int dv[] = new int[256 * divsum];
for (i = 0; i < 256 * divsum; i++) {
dv[i] = (i / divsum);
}
yw = yi = 0;
int[][] stack = new int[div][3];
int stackpointer;
int stackstart;
int[] sir;
int rbs;
int r1 = radius + 1;
int routsum, goutsum, boutsum;
int rinsum, ginsum, binsum;
for (y = 0; y < h; y++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
for (i = -radius; i <= radius; i++) {
p = pix[yi + Math.min(wm, Math.max(i, 0))];
sir = stack[i + radius];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rbs = r1 - Math.abs(i);
rsum += sir[0] * rbs;
gsum += sir[1] * rbs;
bsum += sir[2] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
}
stackpointer = radius;
for (x = 0; x < w; x++) {
r[yi] = dv[rsum];
g[yi] = dv[gsum];
b[yi] = dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (y == 0) {
vmin[x] = Math.min(x + radius + 1, wm);
}
p = pix[yw + vmin[x]];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[(stackpointer) % div];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi++;
}
yw += w;
}
for (x = 0; x < w; x++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
yp = -radius * w;
for (i = -radius; i <= radius; i++) {
yi = Math.max(0, yp) + x;
sir = stack[i + radius];
sir[0] = r[yi];
sir[1] = g[yi];
sir[2] = b[yi];
rbs = r1 - Math.abs(i);
rsum += r[yi] * rbs;
gsum += g[yi] * rbs;
bsum += b[yi] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
if (i < hm) {
yp += w;
}
}
yi = x;
stackpointer = radius;
for (y = 0; y < h; y++) {
// Preserve alpha channel: ( 0xff000000 & pix[yi] )
pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16)
| (dv[gsum] << 8) | dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (x == 0) {
vmin[y] = Math.min(y + r1, hm) * w;
}
p = x + vmin[y];
sir[0] = r[p];
sir[1] = g[p];
sir[2] = b[p];
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[stackpointer];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi += w;
}
}
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
return (bitmap);
}
}
处理前的原始图片pic.png:
处理后的效果(radius=20):
Android高斯模糊、高斯平滑(Gaussian Blur)【2】
Android高斯模糊、高斯平滑(Gaussian Blur)【2】
Android上的高斯模糊效果实现,策略不唯一,在github上有一个开源的实现算法:
https://github.com/paveldudka/blurring
性能上对附录参考文章【1】进行了改进和提升。
Java代码:
package zhangphil.blur;
import android.widget.ImageView;
import android.widget.TextView;
import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.ViewTreeObserver;
public class MainActivity extends Activity {
private ImageView image;
private TextView text;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
image = (ImageView) findViewById(R.id.image);
text = (TextView) findViewById(R.id.text);
image.setImageResource(R.drawable.pic);
applyBlur();
}
private void applyBlur() {
image.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
image.getViewTreeObserver().removeOnPreDrawListener(this);
image.buildDrawingCache();
Bitmap bmp = image.getDrawingCache();
blur(bmp, text);
return true;
}
});
}
//为一个view增加一个以Bitmap bkg为底的高斯模糊图
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void blur(Bitmap bkg, View view) {
float scaleFactor = 1;
float radius = 20;
//性能优先。如果换成这组数据,则速度明显提高
// scaleFactor = 8;
// radius = 2;
Bitmap overlay = Bitmap.createBitmap((int) (view.getMeasuredWidth() / scaleFactor),(int) (view.getMeasuredHeight() / scaleFactor), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(overlay);
canvas.translate(-view.getLeft() / scaleFactor, -view.getTop() / scaleFactor);
canvas.scale(1 / scaleFactor, 1 / scaleFactor);
Paint paint = new Paint();
paint.setFlags(Paint.FILTER_BITMAP_FLAG);
canvas.drawBitmap(bkg, 0, 0, paint);
overlay = FastBlur.doBlur(overlay, (int) radius, true);
view.setBackground(new BitmapDrawable(getResources(), overlay));
}
}
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/pic" />
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:padding="5dip"
android:text="Zhang Phil @ CSDN"
android:textColor="@android:color/white"
android:textSize="25sp"
android:text/>
</FrameLayout>
FastBlur.java工具类:
package zhangphil.blur;
import android.graphics.Bitmap;
import android.util.Log;
public class FastBlur {
public Bitmap fastblur(Bitmap sentBitmap, int radius) {
// Stack Blur v1.0 from
// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
//
// Java Author: Mario Klingemann <mario at quasimondo.com>
// http://incubator.quasimondo.com
// created Feburary 29, 2004
// Android port : Yahel Bouaziz <yahel at kayenko.com>
// http://www.kayenko.com
// ported april 5th, 2012
// This is a compromise between Gaussian Blur and Box blur
// It creates much better looking blurs than Box Blur, but is
// 7x faster than my Gaussian Blur implementation.
//
// I called it Stack Blur because this describes best how this
// filter works internally: it creates a kind of moving stack
// of colors whilst scanning through the image. Thereby it
// just has to add one new block of color to the right side
// of the stack and remove the leftmost color. The remaining
// colors on the topmost layer of the stack are either added on
// or reduced by one, depending on if they are on the right or
// on the left side of the stack.
//
// If you are using this algorithm in your code please add
// the following line:
//
// Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
if (radius < 1) {
return (null);
}
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int[] pix = new int[w * h];
Log.e("pix", w + " " + h + " " + pix.length);
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
int wm = w - 1;
int hm = h - 1;
int wh = w * h;
int div = radius + radius + 1;
int r[] = new int[wh];
int g[] = new int[wh];
int b[] = new int[wh];
int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
int vmin[] = new int[Math.max(w, h)];
int divsum = (div + 1) >> 1;
divsum *= divsum;
int dv[] = new int[256 * divsum];
for (i = 0; i < 256 * divsum; i++) {
dv[i] = (i / divsum);
}
yw = yi = 0;
int[][] stack = new int[div][3];
int stackpointer;
int stackstart;
int[] sir;
int rbs;
int r1 = radius + 1;
int routsum, goutsum, boutsum;
int rinsum, ginsum, binsum;
for (y = 0; y < h; y++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
for (i = -radius; i <= radius; i++) {
p = pix[yi + Math.min(wm, Math.max(i, 0))];
sir = stack[i + radius];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rbs = r1 - Math.abs(i);
rsum += sir[0] * rbs;
gsum += sir[1] * rbs;
bsum += sir[2] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
}
stackpointer = radius;
for (x = 0; x < w; x++) {
r[yi] = dv[rsum];
g[yi] = dv[gsum];
b[yi] = dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (y == 0) {
vmin[x] = Math.min(x + radius + 1, wm);
}
p = pix[yw + vmin[x]];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[(stackpointer) % div];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi++;
}
yw += w;
}
for (x = 0; x < w; x++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
yp = -radius * w;
for (i = -radius; i <= radius; i++) {
yi = Math.max(0, yp) + x;
sir = stack[i + radius];
sir[0] = r[yi];
sir[1] = g[yi];
sir[2] = b[yi];
rbs = r1 - Math.abs(i);
rsum += r[yi] * rbs;
gsum += g[yi] * rbs;
bsum += b[yi] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
if (i < hm) {
yp += w;
}
}
yi = x;
stackpointer = radius;
for (y = 0; y < h; y++) {
// Preserve alpha channel: ( 0xff000000 & pix[yi] )
pix[yi] = ( 0xff000000 & pix[yi] ) | ( dv[rsum] << 16 ) | ( dv[gsum] << 8 ) | dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (x == 0) {
vmin[y] = Math.min(y + r1, hm) * w;
}
p = x + vmin[y];
sir[0] = r[p];
sir[1] = g[p];
sir[2] = b[p];
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[stackpointer];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi += w;
}
}
Log.e("pix", w + " " + h + " " + pix.length);
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
return (bitmap);
}
public static Bitmap doBlur(Bitmap sentBitmap, int radius,
boolean canReuseInBitmap) {
// Stack Blur v1.0 from
// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
//
// Java Author: Mario Klingemann <mario at quasimondo.com>
// http://incubator.quasimondo.com
// created Feburary 29, 2004
// Android port : Yahel Bouaziz <yahel at kayenko.com>
// http://www.kayenko.com
// ported april 5th, 2012
// This is a compromise between Gaussian Blur and Box blur
// It creates much better looking blurs than Box Blur, but is
// 7x faster than my Gaussian Blur implementation.
//
// I called it Stack Blur because this describes best how this
// filter works internally: it creates a kind of moving stack
// of colors whilst scanning through the image. Thereby it
// just has to add one new block of color to the right side
// of the stack and remove the leftmost color. The remaining
// colors on the topmost layer of the stack are either added on
// or reduced by one, depending on if they are on the right or
// on the left side of the stack.
//
// If you are using this algorithm in your code please add
// the following line:
//
// Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
Bitmap bitmap;
if (canReuseInBitmap) {
bitmap = sentBitmap;
} else {
bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
}
if (radius < 1) {
return (null);
}
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int[] pix = new int[w * h];
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
int wm = w - 1;
int hm = h - 1;
int wh = w * h;
int div = radius + radius + 1;
int r[] = new int[wh];
int g[] = new int[wh];
int b[] = new int[wh];
int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
int vmin[] = new int[Math.max(w, h)];
int divsum = (div + 1) >> 1;
divsum *= divsum;
int dv[] = new int[256 * divsum];
for (i = 0; i < 256 * divsum; i++) {
dv[i] = (i / divsum);
}
yw = yi = 0;
int[][] stack = new int[div][3];
int stackpointer;
int stackstart;
int[] sir;
int rbs;
int r1 = radius + 1;
int routsum, goutsum, boutsum;
int rinsum, ginsum, binsum;
for (y = 0; y < h; y++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
for (i = -radius; i <= radius; i++) {
p = pix[yi + Math.min(wm, Math.max(i, 0))];
sir = stack[i + radius];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rbs = r1 - Math.abs(i);
rsum += sir[0] * rbs;
gsum += sir[1] * rbs;
bsum += sir[2] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
}
stackpointer = radius;
for (x = 0; x < w; x++) {
r[yi] = dv[rsum];
g[yi] = dv[gsum];
b[yi] = dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (y == 0) {
vmin[x] = Math.min(x + radius + 1, wm);
}
p = pix[yw + vmin[x]];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[(stackpointer) % div];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi++;
}
yw += w;
}
for (x = 0; x < w; x++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
yp = -radius * w;
for (i = -radius; i <= radius; i++) {
yi = Math.max(0, yp) + x;
sir = stack[i + radius];
sir[0] = r[yi];
sir[1] = g[yi];
sir[2] = b[yi];
rbs = r1 - Math.abs(i);
rsum += r[yi] * rbs;
gsum += g[yi] * rbs;
bsum += b[yi] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
if (i < hm) {
yp += w;
}
}
yi = x;
stackpointer = radius;
for (y = 0; y < h; y++) {
// Preserve alpha channel: ( 0xff000000 & pix[yi] )
pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16)
| (dv[gsum] << 8) | dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (x == 0) {
vmin[y] = Math.min(y + r1, hm) * w;
}
p = x + vmin[y];
sir[0] = r[p];
sir[1] = g[p];
sir[2] = b[p];
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[stackpointer];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi += w;
}
}
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
return (bitmap);
}
}
处理前的图片pic.png:
代码运行结果:
附录参考文章:
【文章1】《Android高斯模糊、高斯平滑(Gaussian Blur)【1】》链接地址:http://blog.csdn.net/zhangphil/article/details/49981499
AR opencv-python | cv2.error: OpenCV(4.5.1) batch_distance.cpp:275: error: (-215:Assertion failed)
如何解决AR opencv-python | cv2.error: OpenCV(4.5.1) batch_distance.cpp:275: error: (-215:Assertion failed)
我决定尝试 Ar 是什么,但遇到了以下问题:
File "C:/Users/Егор/PycharmProjects/ARfotoandvideo/AR.py",line 25,in <module>
macthes = bf.knnMatch(des1,des2,k=2)
cv2.error: OpenCV(4.5.1) C:\\Users\\appveyor\\AppData\\Local\\Temp\\1\\pip-req-build-0ycehs0d\\opencv\\modules\\core\\src\\batch_distance.cpp:275: error: (-215:Assertion Failed) type == src2.type() && src1.cols == src2.cols && (type == CV_32F || type == CV_8U) in function ''cv::batchdistance''
堆栈:
- Windows 8.1 一种语言
- Python 3.7.7
- Pycharm 社区 2018.3.7
- Opencv-python 4.5.1.48
- 网络摄像头 - 在笔记本电脑上,我无法通过 wifi 连接通过 Droidcam 应用程序使用小米手机 Redmy 的摄像头。
信息
我将尝试描述之前发生的错误以及我是如何解决它们的 - 也许这会告诉您需要做什么来解决问题。
在程序执行期间,在从网络摄像头接收图像时发生崩溃 - 正如它本身所表现的那样,当程序启动时,来自网络摄像头的图像提供单色背景(在我的情况下,绿松石) ,当我通过点击X强行关闭所有窗口后,窗口中的数据被刷新并获得正确的图像。 cv2.waitKey (100)
部分解决了这个问题,其中更改 100 的值会导致来自网络摄像头的图像出现,!!!!但 !!!因为有失败,所以没有确定性。
尝试将 cv2.error
中所有可能的错误原因联系起来后,我得出的结论是问题出在 1 和 2 图像上的描述符中。我想指出的是,当网络摄像头相对于图像移动(不是缩放,而是前后移动)时,在 30 种情况下的 1-2 种情况下,它有助于启动程序并正常工作而不会崩溃。>
我的代码
import cv2
import numpy as np
cap = cv2.VideoCapture(1,cv2.CAP_DSHOW)
imgTarget = cv2.imread(''foto.jpg'')
myVid = cv2.VideoCapture(''video.mp4'')
success,imgVideo = myVid.read()
hT,wT,cT = imgTarget.shape
imgVideo = cv2.resize(imgVideo,(wT + 400,hT))
orb = cv2.ORB_create(nfeatures=10)
kp1,des1 = orb.detectAndCompute(imgTarget,None)
imgTarget = cv2.drawKeypoints(imgTarget,kp1,None)
while True:
success,imgWebcam = cap.read()
kp2,des2 = orb.detectAndCompute(imgWebcam,None)
imgWebcam = cv2.drawKeypoints(imgWebcam,kp2,None)
# imgWebcam = cv2.resize(imgWebcam,(wT,hT))
bf = cv2.BFMatcher()
macthes = bf.knnMatch(des1,k=2)
good = []
for m,n in macthes:
if m.distance < 0.75 * n.distance:
good.append(m)
print(len(good))
imgFeatures = cv2.drawMatches(imgTarget,imgWebcam,good,None,flags=2)
if len(good) > 20:
srcPts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1,1,2)
dstPts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1,2)
matrix,mask = cv2.findHomography(srcPts,dstPts,cv2.RANSAC,5)
print(matrix)
pts = np.float32([[0,0],[0,wT],[wT,hT],0]]).reshape(-1,2)
dst = cv2.perspectiveTransform(pts,matrix)
img2 = cv2.polylines(imgWebcam,[np.int32(dst)],True,(255,255),3)
cv2.imshow(''img2'',img2)
cv2.imshow(''imgFeatures'',imgFeatures)
cv2.imshow(''imgTarget'',imgTarget)
cv2.imshow(''myVid'',imgVideo)
cv2.imshow(''imgWebcam'',imgWebcam)
cv2.waitKey(100)
我们今天的关于Python OpenCV 图片模糊操作 blur 与 medianBlur和python opencv图片处理的分享已经告一段落,感谢您的关注,如果您想了解更多关于36 篇博文带你学完 opencv :python+opencv 进阶版学习笔记目录、Android高斯模糊、高斯平滑(Gaussian Blur)【1】、Android高斯模糊、高斯平滑(Gaussian Blur)【2】、AR opencv-python | cv2.error: OpenCV(4.5.1) batch_distance.cpp:275: error: (-215:Assertion failed)的相关信息,请在本站查询。
本文标签: