索贝尔过滤器很奇怪
Sobel filter is strange
最近我正在准备Low Poly
这样的:
我的第一件事是提取输入的一些点image.I想尝试Sobel
进行检测并且我已经阅读soble article。
现在我遇到了不知道如何实现 sobel 的问题 filter.Folowing 是我的尝试:
首先->从输入图像中获取灰度数据
try {
mImage = ImageIO.read(new File("D:\Documents\Pictures\engine.png"));
} catch (IOException e) {
e.printStackTrace();
}
mWidth = mImage.getWidth();
mHeight = mImage.getHeight();
mNewImage = new BufferedImage(mWidth, mHeight, mImage.getType());
mGrayData = new int[mWidth * mHeight];
// get pixel data from image
for (int i = 0; i < mHeight; i++) {
for (int j = 0; j < mWidth; j++) {
int rgb = mImage.getRGB(j, i);
int r = (rgb >> 16) & 0xff;
int g = (rgb >> 8) & 0xff;
int b = rgb & 0xff;
int grayLevel = (r + g + b) / 3;
mGrayData[i * mWidth + j] = grayLevel;
}
}
然后->计算每个点的梯度
private int[] getGradient() {
int[] gradient = new int[mWidth * mHeight];
for (int x=1;x<mWidth-1;x++){
for (int y=1;y<mHeight-1;y++){
int grayX = getGrayPoint(x+1,y-1)+2*getGrayPoint(x+1,y)+getGrayPoint(x+1,y+1)-
(getGrayPoint(x-1,y-1)+2*getGrayPoint(x-1,y)+getGrayPoint(x-1,y+1));
int grayY = (getGrayPoint(x-1, y+1) + 2*getGrayPoint(x,y+1)+getGrayPoint(x+1,y+1))-
(getGrayPoint(x-1,y-1) + 2*getGrayPoint(x,y-1) + getGrayPoint(x+1,y-1));
gradient[x+y*mWidth] = (int) Math.sqrt(grayX*grayX+grayY*grayY);
}
}
return gradient;
}
最后 -> 使用以上渐变创建新图像
private void createImage() {
int[] gradient = getGradient();
for (int y = 1; y < mHeight - 1; ++y)
for (int x = 1; x < mWidth - 1; ++x)
mNewImage.setRGB(x,y,gradient[y * mWidth + x]);
File file = new File("D:\Documents\Pictures\engine3.png");
if (!file.exists()) {
file.getParentFile().mkdir();
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
ImageIO.write(mNewImage, "png", file);
} catch (IOException e) {
e.printStackTrace();
}
}
原图
它应该是什么样子?
我得到了什么
颜色有点蓝好奇怪
编辑 1:
现在我得到:
为什么这么黑
你在这里设置颜色:
mNewImage.setRGB(x,y,gradient[y * mWidth + x]);
您没有采取任何措施来确保红色、绿色和蓝色通道中的值相同。
整数的32位用来打包4个8位通道,分别代表alpha、红、绿、蓝。
0x01234567 = overall color
01 = alpha
23 = red
45 = green
67 = blue
您只设置了一个值;这看起来没有超出 0 到 255 的范围,因此您实际上只是在蓝色通道中设置位。 (假设您还使用了 RGB 颜色模型,而不是 ARGB,这就是像素不完全透明的原因)。
将三个通道设置为相同的值(并将值限制在 0-255 之间,以免不小心在其他通道中设置位):
int gray = Math.max(0, Math.min(gradient[...], 255);
int color = (0xff << 24) | (gray << 16) | (gray << 8) | (gray);
// Alpha Red Green Blue
请注意,您可能还想缩放渐变值,以便为具有最大渐变的点指定灰度值 255:
int maxGradient = 0;
for (int g : gradient) {
maxGradient = Math.max(maxGradient, g);
}
然后:
int gray = Math.max(0, gradient) * 255 / maxGradient;
(您不再需要将其限制为最多 255)。
此外,您可能希望制作渐变数组 float[]
或 double[]
(并为 maxGradient
使用相同的元素类型),以便获得较少的量化输出。
最近我正在准备Low Poly
这样的:
我的第一件事是提取输入的一些点image.I想尝试Sobel
进行检测并且我已经阅读soble article。
现在我遇到了不知道如何实现 sobel 的问题 filter.Folowing 是我的尝试:
首先->从输入图像中获取灰度数据
try {
mImage = ImageIO.read(new File("D:\Documents\Pictures\engine.png"));
} catch (IOException e) {
e.printStackTrace();
}
mWidth = mImage.getWidth();
mHeight = mImage.getHeight();
mNewImage = new BufferedImage(mWidth, mHeight, mImage.getType());
mGrayData = new int[mWidth * mHeight];
// get pixel data from image
for (int i = 0; i < mHeight; i++) {
for (int j = 0; j < mWidth; j++) {
int rgb = mImage.getRGB(j, i);
int r = (rgb >> 16) & 0xff;
int g = (rgb >> 8) & 0xff;
int b = rgb & 0xff;
int grayLevel = (r + g + b) / 3;
mGrayData[i * mWidth + j] = grayLevel;
}
}
然后->计算每个点的梯度
private int[] getGradient() {
int[] gradient = new int[mWidth * mHeight];
for (int x=1;x<mWidth-1;x++){
for (int y=1;y<mHeight-1;y++){
int grayX = getGrayPoint(x+1,y-1)+2*getGrayPoint(x+1,y)+getGrayPoint(x+1,y+1)-
(getGrayPoint(x-1,y-1)+2*getGrayPoint(x-1,y)+getGrayPoint(x-1,y+1));
int grayY = (getGrayPoint(x-1, y+1) + 2*getGrayPoint(x,y+1)+getGrayPoint(x+1,y+1))-
(getGrayPoint(x-1,y-1) + 2*getGrayPoint(x,y-1) + getGrayPoint(x+1,y-1));
gradient[x+y*mWidth] = (int) Math.sqrt(grayX*grayX+grayY*grayY);
}
}
return gradient;
}
最后 -> 使用以上渐变创建新图像
private void createImage() {
int[] gradient = getGradient();
for (int y = 1; y < mHeight - 1; ++y)
for (int x = 1; x < mWidth - 1; ++x)
mNewImage.setRGB(x,y,gradient[y * mWidth + x]);
File file = new File("D:\Documents\Pictures\engine3.png");
if (!file.exists()) {
file.getParentFile().mkdir();
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
ImageIO.write(mNewImage, "png", file);
} catch (IOException e) {
e.printStackTrace();
}
}
原图
它应该是什么样子?
我得到了什么
颜色有点蓝好奇怪
编辑 1:
现在我得到:
为什么这么黑
你在这里设置颜色:
mNewImage.setRGB(x,y,gradient[y * mWidth + x]);
您没有采取任何措施来确保红色、绿色和蓝色通道中的值相同。
整数的32位用来打包4个8位通道,分别代表alpha、红、绿、蓝。
0x01234567 = overall color
01 = alpha
23 = red
45 = green
67 = blue
您只设置了一个值;这看起来没有超出 0 到 255 的范围,因此您实际上只是在蓝色通道中设置位。 (假设您还使用了 RGB 颜色模型,而不是 ARGB,这就是像素不完全透明的原因)。
将三个通道设置为相同的值(并将值限制在 0-255 之间,以免不小心在其他通道中设置位):
int gray = Math.max(0, Math.min(gradient[...], 255);
int color = (0xff << 24) | (gray << 16) | (gray << 8) | (gray);
// Alpha Red Green Blue
请注意,您可能还想缩放渐变值,以便为具有最大渐变的点指定灰度值 255:
int maxGradient = 0;
for (int g : gradient) {
maxGradient = Math.max(maxGradient, g);
}
然后:
int gray = Math.max(0, gradient) * 255 / maxGradient;
(您不再需要将其限制为最多 255)。
此外,您可能希望制作渐变数组 float[]
或 double[]
(并为 maxGradient
使用相同的元素类型),以便获得较少的量化输出。