Java 模糊图像
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29295929/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java blur Image
提问by Prashant Thorat
I am trying to blur the image
我正在尝试模糊图像
int radius = 11;
int size = radius * 2 + 1;
float weight = 1.0f / (size * size);
float[] data = new float[size * size];
for (int i = 0; i < data.length; i++) {
data[i] = weight;
}
Kernel kernel = new Kernel(size, size, data);
ConvolveOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
//tbi is BufferedImage
BufferedImage i = op.filter(tbi, null);
It will blur the image but not all portion of the image.
它会模糊图像,但不会模糊图像的所有部分。
Where I am missing so that it will blur complete image. Without any path .
我失踪的地方,所以它会模糊完整的图像。没有任何路径。
回答by haraldK
The standard Java ConvolveOp
only has the two options EDGE_ZERO_FILL
and EDGE_NO_OP
. What you want is the options from the JAI equivalent (ConvolveDescriptor), which is EDGE_REFLECT
(or EDGE_WRAP
, if you want repeating patterns).
标准 JavaConvolveOp
只有两个选项EDGE_ZERO_FILL
和EDGE_NO_OP
。您想要的是 JAI 等效项 ( ConvolveDescriptor) 中的选项,即EDGE_REFLECT
(或者EDGE_WRAP
,如果您想要重复模式)。
If you don't want to use JAI, you can implement this yourself, by copying your image to a larger image, stretching or wrapping the edges, apply the convolve op, then cut off the edges (similar to the technique described in the "Working on the Edge" section of the articleposted by @halex in the comments section, but according to that article, you can also just leave the edges transparent).
如果您不想使用 JAI,您可以自己实现,方法是将您的图像复制到更大的图像,拉伸或包裹边缘,应用卷积运算,然后切掉边缘(类似于“在评论部分@halex 发布的文章的“在边缘上工作”部分,但根据该文章,您也可以让边缘保持透明)。
For simplicity, you can just use my implementation called ConvolveWithEdgeOp
which does the above (BSD license).
为简单起见,您可以使用我的实现,称为执行ConvolveWithEdgeOp
上述操作(BSD 许可)。
The code will be similar to what you had originally:
该代码将类似于您原来的代码:
// ...kernel setup as before...
Kernel kernel = new Kernel(size, size, data);
BufferedImageOp op = new ConvolveWithEdgeOp(kernel, ConvolveOp.EDGE_REFLECT, null);
BufferedImage blurred = op.filter(original, null);
The filter should work like any other BufferedImageOp
, and should work with any BufferedImage
.
过滤器应该像任何其他过滤器一样工作BufferedImageOp
,并且应该与任何BufferedImage
.
回答by Jesper
That is because you are using ConvolveOp.EDGE_NO_OP
in this line:
那是因为您ConvolveOp.EDGE_NO_OP
在这一行中使用:
ConvolveOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
The API documentationsays:
该API文档说:
Pixels at the edge of the source image are copied to the corresponding pixels in the destination without modification.
源图像边缘的像素不加修改地复制到目标中的相应像素。
Try EDGE_ZERO_FILL
- that will give you black borders.
尝试EDGE_ZERO_FILL
- 这会给你黑色边框。
You can also try to cut off the edges after blurring.
您也可以尝试在模糊后切掉边缘。
The reason for why it can't do the edges has to do with how the algorithm works.
不能做边的原因与算法的工作方式有关。
回答by Tomas
You can't blur one pixel. This sounds obvious, but when you think about it, what is the minimum? To blur a pixel, you need neighboring pixels.
你不能模糊一个像素。这听起来很明显,但仔细想想,最低限度是多少?要模糊像素,您需要相邻的像素。
The problem here is that at the edges and corners, the pixels have too few neighbours – the blur algorith has too few pixels to use. It has no pixels "outside" the image with which to blur, so it will just leave those as-is.
这里的问题是在边缘和角落,像素的邻居太少——模糊算法使用的像素太少。它没有要模糊的图像“外部”像素,因此它只会保持原样。
The solution is either to extend the picture somehow (do you have a larger source image available?), or to cut off the non-blurred bits when you are done. Both are essentially the same.
解决方案要么以某种方式扩展图片(您有更大的可用源图像吗?),要么在完成后切断未模糊的部分。两者本质上是一样的。
回答by Rabbit Guy
I found this once when I was looking for a blur ability for documents when the ConvolveOp class didn't cut it (for the reasons you are running into). It does a Gaussian blur which is the most natural blur imho... Hopefully it will help you. I retrieved it from this webpage: Java Image Processing...
当我在 ConvolveOp 类没有切割它时(出于您遇到的原因)寻找文档的模糊能力时,我发现了一次。它做了一个高斯模糊,这是最自然的模糊,恕我直言......希望它会帮助你。我从这个网页中检索到它:Java Image Processing...
/*
** Copyright 2005 Huxtable.com. All rights reserved.
*/
package com.jhlabs.image;
import java.awt.image.*;
/**
* A filter which applies Gaussian blur to an image. This is a subclass of ConvolveFilter
* which simply creates a kernel with a Gaussian distribution for blurring.
* @author Jerry Huxtable
*/
public class GaussianFilter extends ConvolveFilter {
static final long serialVersionUID = 5377089073023183684L;
protected float radius;
protected Kernel kernel;
/**
* Construct a Gaussian filter
*/
public GaussianFilter() {
this(2);
}
/**
* Construct a Gaussian filter
* @param radius blur radius in pixels
*/
public GaussianFilter(float radius) {
setRadius(radius);
}
/**
* Set the radius of the kernel, and hence the amount of blur. The bigger the radius, the longer this filter will take.
* @param radius the radius of the blur in pixels.
*/
public void setRadius(float radius) {
this.radius = radius;
kernel = makeKernel(radius);
}
/**
* Get the radius of the kernel.
* @return the radius
*/
public float getRadius() {
return radius;
}
public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
int width = src.getWidth();
int height = src.getHeight();
if ( dst == null )
dst = createCompatibleDestImage( src, null );
int[] inPixels = new int[width*height];
int[] outPixels = new int[width*height];
src.getRGB( 0, 0, width, height, inPixels, 0, width );
convolveAndTranspose(kernel, inPixels, outPixels, width, height, alpha, CLAMP_EDGES);
convolveAndTranspose(kernel, outPixels, inPixels, height, width, alpha, CLAMP_EDGES);
dst.setRGB( 0, 0, width, height, inPixels, 0, width );
return dst;
}
public static void convolveAndTranspose(Kernel kernel, int[] inPixels, int[] outPixels, int width, int height, boolean alpha, int edgeAction) {
float[] matrix = kernel.getKernelData( null );
int cols = kernel.getWidth();
int cols2 = cols/2;
for (int y = 0; y < height; y++) {
int index = y;
int ioffset = y*width;
for (int x = 0; x < width; x++) {
float r = 0, g = 0, b = 0, a = 0;
int moffset = cols2;
for (int col = -cols2; col <= cols2; col++) {
float f = matrix[moffset+col];
if (f != 0) {
int ix = x+col;
if ( ix < 0 ) {
if ( edgeAction == CLAMP_EDGES )
ix = 0;
else if ( edgeAction == WRAP_EDGES )
ix = (x+width) % width;
} else if ( ix >= width) {
if ( edgeAction == CLAMP_EDGES )
ix = width-1;
else if ( edgeAction == WRAP_EDGES )
ix = (x+width) % width;
}
int rgb = inPixels[ioffset+ix];
a += f * ((rgb >> 24) & 0xff);
r += f * ((rgb >> 16) & 0xff);
g += f * ((rgb >> 8) & 0xff);
b += f * (rgb & 0xff);
}
}
int ia = alpha ? PixelUtils.clamp((int)(a+0.5)) : 0xff;
int ir = PixelUtils.clamp((int)(r+0.5));
int ig = PixelUtils.clamp((int)(g+0.5));
int ib = PixelUtils.clamp((int)(b+0.5));
outPixels[index] = (ia << 24) | (ir << 16) | (ig << 8) | ib;
index += height;
}
}
}
/**
* Make a Gaussian blur kernel.
*/
public static Kernel makeKernel(float radius) {
int r = (int)Math.ceil(radius);
int rows = r*2+1;
float[] matrix = new float[rows];
float sigma = radius/3;
float sigma22 = 2*sigma*sigma;
float sigmaPi2 = 2*ImageMath.PI*sigma;
float sqrtSigmaPi2 = (float)Math.sqrt(sigmaPi2);
float radius2 = radius*radius;
float total = 0;
int index = 0;
for (int row = -r; row <= r; row++) {
float distance = row*row;
if (distance > radius2)
matrix[index] = 0;
else
matrix[index] = (float)Math.exp(-(distance)/sigma22) / sqrtSigmaPi2;
total += matrix[index];
index++;
}
for (int i = 0; i < rows; i++)
matrix[i] /= total;
return new Kernel(rows, 1, matrix);
}
public String toString() {
return "Blur/Gaussian Blur...";
}
}
回答by critichu
If you frequently deal with pictures in your application, you may want to consider using the ImageJ API: It packs functionality on quite a lot of image processing tasks, including blurring.
如果您经常在应用程序中处理图片,您可能需要考虑使用 ImageJ API:它包含了大量图像处理任务的功能,包括模糊处理。
Their Gaussian Blur filter will blur right to the edge of the picture, by making the following assumption
通过做出以下假设,他们的高斯模糊过滤器将模糊到图片的边缘
{...} it assumes that out-of-image pixels have a value equal to the nearest edge pixel {...}
{...} 它假设图像外像素的值等于最近的边缘像素 {...}
Even if you don't want to change your code to use the ImageJ API, you may still find the above assumption useful to solving your problem.
即使您不想更改代码以使用 ImageJ API,您仍然可能会发现上述假设对解决您的问题很有用。
For more info, check out the GaussianBlur filter in the API documentation: http://rsb.info.nih.gov/ij/developer/api/ij/plugin/filter/GaussianBlur.html
有关更多信息,请查看 API 文档中的 GaussianBlur 过滤器:http: //rsb.info.nih.gov/ij/developer/api/ij/plugin/filter/GaussianBlur.html
回答by Aniket Patil
You can use opencv library to make complete image blur.
您可以使用 opencv 库来制作完整的图像模糊。