我试图模糊图像
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);
它会模糊图像,但不会模糊图像的所有部分。
我失踪的地方会使整个图像模糊不清。没有任何道路。
答案 0 :(得分:8)
标准Java ConvolveOp
只有两个选项EDGE_ZERO_FILL
和EDGE_NO_OP
。你想要的是JAI等价物(ConvolveDescriptor)中的选项,EDGE_REFLECT
(或EDGE_WRAP
,如果你想重复模式)。
如果你不想使用JAI,你可以自己实现,通过将图像复制到更大的图像,拉伸或包裹边缘,应用卷积操作,然后切除边缘(类似于@halex在评论部分发布的the article部分&#34;在边缘工作&#34;部分中描述的技术,但根据该文章,您也可以保持边缘透明。
为简单起见,您可以使用my implementation called ConvolveWithEdgeOp
执行上述操作(BSD许可证)。
代码与您原来的代码类似:
// ...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);
过滤器应该像其他任何BufferedImageOp
一样工作,并且可以与任何BufferedImage
一起使用。
答案 1 :(得分:2)
这是因为您在此行中使用ConvolveOp.EDGE_NO_OP
:
ConvolveOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
源图像边缘的像素将被复制到目标中的相应像素而不进行修改。
尝试EDGE_ZERO_FILL
- 这将为您提供黑色边框。
您也可以尝试在模糊后剪掉边缘。
为什么它不能做边缘的原因与算法的工作方式有关。
答案 2 :(得分:1)
您可以使用opencv库来完成图像模糊。
答案 3 :(得分:0)
你无法模糊一个像素。这听起来很明显,但是当你想到它时,最低限度是多少?要模糊像素,您需要相邻的像素。
这里的问题是在边缘和角落处,像素的邻居太少 - 模糊算法的像素太少而无法使用。它没有“模糊”图像“外部”的像素,因此它将保持原样。
解决方案是以某种方式扩展图片(你有更大的源图像吗?),或者在你完成时切断非模糊的位。两者基本相同。
答案 4 :(得分:0)
当我在寻找ConvolveOp类没有剪切它的文档的模糊能力时(因为你遇到的原因),我发现了这一次。它做了高斯模糊,这是最自然的模糊imho ...希望它会帮助你。我从这个网页上检索了它: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...";
}
}
答案 5 :(得分:0)
如果您经常处理应用程序中的图片,您可能需要考虑使用ImageJ API:它包含很多图像处理任务的功能,包括模糊。
通过进行以下假设,他们的高斯模糊滤镜将模糊到画面的边缘
{...}它假设图像外像素的值等于最近的边缘像素{...}
即使您不想更改代码以使用ImageJ API,您仍然可以发现上述假设对解决您的问题很有用。
有关详细信息,请查看API文档中的GaussianBlur过滤器: http://rsb.info.nih.gov/ij/developer/api/ij/plugin/filter/GaussianBlur.html
答案 6 :(得分:0)
我总是这样:
public BufferedImage diagonalBlur(int range, int angle)
{
BufferedImage b = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g = b.createGraphics();
for(int x = 0; x < main_image.getWidth(); x++)
{
for(int y = 0; y < main_image.getHeight(); y++)
int red[] = new int[range * 2], green[] = new int[range * 2], blue[] = new int[range * 2];
int pixels[] = new int[range * 2];
for(int i = 0; i < pixels.length; i++)
{
pixels[i] = main_image.getRGB(clamp(x - clamp(range / 2, 0, range) + i, 0, main_image.getWidth() - 1), clamp(y - clamp(range / 2, 0, range) + (int)(i * Math.toRadians(angle)), 0, main_image.getHeight() - 1));
red[i] = (pixels[i] >> 16) & 0xff;
green[i] = (pixels[i] >> 8) & 0xff;
blue[i] = (pixels[i]) & 0xff;
}
int red_t = 0, green_t = 0, blue_t = 0;
for(int i = 0; i < pixels.length; i++)
{
red_t += red[i];
green_t += green[i];
blue_t += blue[i];
}
int r = red_t / (range * 2);
int gr = green_t / (range * 2);
int bl = blue_t / (range * 2);
//System.out.println(r + ", " + gr + ", " + bl);
g.setColor(new Color(r, gr, bl));
g.fillRect(x, y, 1, 1);
}
}
g.dispose();
return b;
然后,按照以下方式进行操作:
public static void main(String a[])
{
File f = new File("path");
try{
ImageIO.write(diagonalBlur(10, 69), "png", f);
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
那应该将文件另存为BufferedImage。当然,您需要参考图像。 在代码中,我使用了main_image,但这是我之前创建的变量:
public BufferedImage main_image;
启动它我用
try
{
main_image = ImageIO.read(new File("path"));
}
catch(IOException e)
{
e.printStackTrace();
}
在主要方法中。
添加一些JFrame代码,使我可以执行此操作:
blur
如果要使高斯模糊,只需将red
,green
,blue
和pixels
变成二维数组,然后对y轴。
希望我能帮上忙。