Java - 이미지에서 픽셀 배열 가져오기
픽셀 데이터를 가장 빨리 얻을 수 있는 방법을 찾고 있습니다(폼 내).int[][]( )을 참조해 주세요.제 목표는 픽셀 주소를 지정할 수 있는 것입니다.(x, y)를 사용하여 이미지에서int[x][y]. 내가 찾은 모든 방법은 이 작업을 수행하지 않습니다(대부분이 반환됨).int[]s)
그냥 같은 주제를 가지고 놀고 있었어요 그게 픽셀에 가장 빨리 접근할 수 있는 방법이죠현재 두 가지 방법을 알고 있습니다.
- Buffered Image 사용
getRGB()메서드는 @tskuzy의 답변에 설명되어 있습니다. 다음을 사용하여 픽셀 배열에 직접 액세스합니다.
byte[] pixels = ((DataBufferByte) bufferedImage.getRaster().getDataBuffer()).getData();
큰 이미지로 작업하는 경우 퍼포먼스가 문제가 된다면 첫 번째 방법은 결코 바람직한 방법이 아닙니다.그getRGB()method는 알파, 레드, 그린 및 블루 값을 하나의 int로 조합한 후 결과를 반환합니다.대부분의 경우, 이러한 값을 되돌리려면 그 반대의 작업을 수행합니다.
두 번째 방법에서는 각 픽셀에 대해 직접 빨간색, 녹색 및 파란색 값을 반환하고 알파 채널이 있는 경우 알파 값을 추가합니다.이 방법을 사용하는 것은 지수를 계산하는 측면에서 더 어렵지만 첫 번째 접근법보다 훨씬 빠르다.
어플리케이션에서는 첫 번째 어프로치에서 두 번째 어프로치로 전환하는 것만으로 픽셀 처리 시간을 90% 이상 단축할 수 있었습니다.
다음은 두 가지 접근 방식을 비교하기 위해 설정한 비교입니다.
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.IOException;
import javax.imageio.ImageIO;
public class PerformanceTest {
public static void main(String[] args) throws IOException {
BufferedImage hugeImage = ImageIO.read(PerformanceTest.class.getResource("12000X12000.jpg"));
System.out.println("Testing convertTo2DUsingGetRGB:");
for (int i = 0; i < 10; i++) {
long startTime = System.nanoTime();
int[][] result = convertTo2DUsingGetRGB(hugeImage);
long endTime = System.nanoTime();
System.out.println(String.format("%-2d: %s", (i + 1), toString(endTime - startTime)));
}
System.out.println("");
System.out.println("Testing convertTo2DWithoutUsingGetRGB:");
for (int i = 0; i < 10; i++) {
long startTime = System.nanoTime();
int[][] result = convertTo2DWithoutUsingGetRGB(hugeImage);
long endTime = System.nanoTime();
System.out.println(String.format("%-2d: %s", (i + 1), toString(endTime - startTime)));
}
}
private static int[][] convertTo2DUsingGetRGB(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
int[][] result = new int[height][width];
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
result[row][col] = image.getRGB(col, row);
}
}
return result;
}
private static int[][] convertTo2DWithoutUsingGetRGB(BufferedImage image) {
final byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
final int width = image.getWidth();
final int height = image.getHeight();
final boolean hasAlphaChannel = image.getAlphaRaster() != null;
int[][] result = new int[height][width];
if (hasAlphaChannel) {
final int pixelLength = 4;
for (int pixel = 0, row = 0, col = 0; pixel + 3 < pixels.length; pixel += pixelLength) {
int argb = 0;
argb += (((int) pixels[pixel] & 0xff) << 24); // alpha
argb += ((int) pixels[pixel + 1] & 0xff); // blue
argb += (((int) pixels[pixel + 2] & 0xff) << 8); // green
argb += (((int) pixels[pixel + 3] & 0xff) << 16); // red
result[row][col] = argb;
col++;
if (col == width) {
col = 0;
row++;
}
}
} else {
final int pixelLength = 3;
for (int pixel = 0, row = 0, col = 0; pixel + 2 < pixels.length; pixel += pixelLength) {
int argb = 0;
argb += -16777216; // 255 alpha
argb += ((int) pixels[pixel] & 0xff); // blue
argb += (((int) pixels[pixel + 1] & 0xff) << 8); // green
argb += (((int) pixels[pixel + 2] & 0xff) << 16); // red
result[row][col] = argb;
col++;
if (col == width) {
col = 0;
row++;
}
}
}
return result;
}
private static String toString(long nanoSecs) {
int minutes = (int) (nanoSecs / 60000000000.0);
int seconds = (int) (nanoSecs / 1000000000.0) - (minutes * 60);
int millisecs = (int) ( ((nanoSecs / 1000000000.0) - (seconds + minutes * 60)) * 1000);
if (minutes == 0 && seconds == 0)
return millisecs + "ms";
else if (minutes == 0 && millisecs == 0)
return seconds + "s";
else if (seconds == 0 && millisecs == 0)
return minutes + "min";
else if (minutes == 0)
return seconds + "s " + millisecs + "ms";
else if (seconds == 0)
return minutes + "min " + millisecs + "ms";
else if (millisecs == 0)
return minutes + "min " + seconds + "s";
return minutes + "min " + seconds + "s " + millisecs + "ms";
}
}
결과를 추측할 수 있습니까?;)
Testing convertTo2DUsingGetRGB:
1 : 16s 911ms
2 : 16s 730ms
3 : 16s 512ms
4 : 16s 476ms
5 : 16s 503ms
6 : 16s 683ms
7 : 16s 477ms
8 : 16s 373ms
9 : 16s 367ms
10: 16s 446ms
Testing convertTo2DWithoutUsingGetRGB:
1 : 1s 487ms
2 : 1s 940ms
3 : 1s 785ms
4 : 1s 848ms
5 : 1s 624ms
6 : 2s 13ms
7 : 1s 968ms
8 : 1s 864ms
9 : 1s 673ms
10: 2s 86ms
BUILD SUCCESSFUL (total time: 3 minutes 10 seconds)
이런 거?
int[][] pixels = new int[w][h];
for( int i = 0; i < w; i++ )
for( int j = 0; j < h; j++ )
pixels[i][j] = img.getRGB( i, j );
나는 Mota의 답변이 나에게 10배의 속도를 증가시켰다는 것을 알았다 - 그래서 Mota에게 감사한다.
BufferedImage를 컨스트럭터로 가져와서 그에 상응하는 getRBG(x,y) 메서드를 공개하는 편리한 클래스로 코드를 정리했습니다.이 메서드는 BufferedImage.getRGB(x,y)를 사용하여 코드 대체를 드롭합니다.
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
public class FastRGB
{
private int width;
private int height;
private boolean hasAlphaChannel;
private int pixelLength;
private byte[] pixels;
FastRGB(BufferedImage image)
{
pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
width = image.getWidth();
height = image.getHeight();
hasAlphaChannel = image.getAlphaRaster() != null;
pixelLength = 3;
if (hasAlphaChannel)
{
pixelLength = 4;
}
}
int getRGB(int x, int y)
{
int pos = (y * pixelLength * width) + (x * pixelLength);
int argb = -16777216; // 255 alpha
if (hasAlphaChannel)
{
argb = (((int) pixels[pos++] & 0xff) << 24); // alpha
}
argb += ((int) pixels[pos++] & 0xff); // blue
argb += (((int) pixels[pos++] & 0xff) << 8); // green
argb += (((int) pixels[pos++] & 0xff) << 16); // red
return argb;
}
}
단색 비트맵에서 Buffered Image를 가져오지 않는 한 Mota의 답변은 훌륭합니다.흑백 비트맵의 픽셀 값은 2개뿐입니다(예: 0 = 검은색 및 1 = 흰색).흑백 비트맵을 사용하면
final byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
call은 각 바이트에 여러 픽셀이 포함되도록 원시 픽셀 배열 데이터를 반환합니다.
따라서 흑백 비트맵 이미지를 사용하여 Buffered Image 개체를 만들 때 사용하는 알고리즘은 다음과 같습니다.
/**
* This returns a true bitmap where each element in the grid is either a 0
* or a 1. A 1 means the pixel is white and a 0 means the pixel is black.
*
* If the incoming image doesn't have any pixels in it then this method
* returns null;
*
* @param image
* @return
*/
public static int[][] convertToArray(BufferedImage image)
{
if (image == null || image.getWidth() == 0 || image.getHeight() == 0)
return null;
// This returns bytes of data starting from the top left of the bitmap
// image and goes down.
// Top to bottom. Left to right.
final byte[] pixels = ((DataBufferByte) image.getRaster()
.getDataBuffer()).getData();
final int width = image.getWidth();
final int height = image.getHeight();
int[][] result = new int[height][width];
boolean done = false;
boolean alreadyWentToNextByte = false;
int byteIndex = 0;
int row = 0;
int col = 0;
int numBits = 0;
byte currentByte = pixels[byteIndex];
while (!done)
{
alreadyWentToNextByte = false;
result[row][col] = (currentByte & 0x80) >> 7;
currentByte = (byte) (((int) currentByte) << 1);
numBits++;
if ((row == height - 1) && (col == width - 1))
{
done = true;
}
else
{
col++;
if (numBits == 8)
{
currentByte = pixels[++byteIndex];
numBits = 0;
alreadyWentToNextByte = true;
}
if (col == width)
{
row++;
col = 0;
if (!alreadyWentToNextByte)
{
currentByte = pixels[++byteIndex];
numBits = 0;
}
}
}
}
return result;
}
필요에 따라서, 다음의 조작을 실시합니다.
BufferedImage imgBuffer = ImageIO.read(new File("c:\\image.bmp"));
byte[] pixels = (byte[])imgBuffer.getRaster().getDataElements(0, 0, imgBuffer.getWidth(), imgBuffer.getHeight(), null);
다음으로 FastRGB의 실장을 나타냅니다.
public class FastRGB {
public int width;
public int height;
private boolean hasAlphaChannel;
private int pixelLength;
private byte[] pixels;
FastRGB(BufferedImage image) {
pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
width = image.getWidth();
height = image.getHeight();
hasAlphaChannel = image.getAlphaRaster() != null;
pixelLength = 3;
if (hasAlphaChannel)
pixelLength = 4;
}
short[] getRGB(int x, int y) {
int pos = (y * pixelLength * width) + (x * pixelLength);
short rgb[] = new short[4];
if (hasAlphaChannel)
rgb[3] = (short) (pixels[pos++] & 0xFF); // Alpha
rgb[2] = (short) (pixels[pos++] & 0xFF); // Blue
rgb[1] = (short) (pixels[pos++] & 0xFF); // Green
rgb[0] = (short) (pixels[pos++] & 0xFF); // Red
return rgb;
}
}
이게 뭐야?
Buffered Image의 getRGB 메서드를 사용하여 이미지를 픽셀 단위로 읽는 것은 매우 느립니다.이 클래스는 이를 위한 솔루션입니다.
이 개념은 Buffered Image 인스턴스를 제공하여 개체를 구성하면 모든 데이터를 한 번에 읽고 배열에 저장하는 것입니다.픽셀을 가져오려면 getRGB를 호출합니다.
의존 관계
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
고려 사항.
FastRGB는 픽셀을 훨씬 빠르게 읽을 수 있지만 이미지 복사본을 저장하기만 하면 되기 때문에 메모리 사용량이 증가할 수 있습니다.따라서 메모리에 4MB의 BufferedImage가 있는 경우 FastRGB 인스턴스를 생성하면 메모리 사용량이 8MB가 됩니다. 단, FastRGB를 생성한 후에는 BufferedImage 인스턴스를 재사용할 수 있습니다.
Out Of Memory(메모리 부족)에 빠지지 않도록 주의해 주세요.RAM이 병목현상이 되는 Android 폰 등의 디바이스에서 사용하는 경우는 예외입니다.
이 방법은 효과가 있었습니다.
BufferedImage bufImgs = ImageIO.read(new File("c:\\adi.bmp"));
double[][] data = new double[][];
bufImgs.getData().getPixels(0,0,bufImgs.getWidth(),bufImgs.getHeight(),data[i]);
언급URL : https://stackoverflow.com/questions/6524196/java-get-pixel-array-from-image
'source' 카테고리의 다른 글
| JavaScript 변수에 PHP 문자열 전달(및 줄바꿈 이스케이프) (0) | 2022.12.01 |
|---|---|
| 휴지 상태 4에서5로의 이행 (0) | 2022.12.01 |
| 정규식 일치 후에 이어지는 텍스트 가져오기 (0) | 2022.12.01 |
| JavaScript에서 "엄격한 사용"은 무엇을 하며, 그 배경은 무엇입니까? (0) | 2022.11.22 |
| 로그인 메서드는 푸시 경로 전에 디스패치액션이 완료될 때까지 기다리지 않습니다. (0) | 2022.11.22 |