Bối cảnh: Tôi đang cố gắng tạo hoạt ảnh bằng java. Hoạt ảnh chỉ đơn giản là chụp một hình ảnh và làm cho nó xuất hiện từ các pixel tối nhất đến điểm ảnh nhỏ nhất.Hiệu suất nhanh nhất lọc hình ảnh
Sự cố: Thuật toán nội bộ xác định chuyển đổi pixel không phải là vấn đề của tôi. Tôi mới sử dụng Java và Máy tính nói chung. Tôi đã thực hiện một chút nghiên cứu và biết rằng có rất nhiều API giúp với bộ lọc/chuyển đổi hình ảnh. Vấn đề của tôi là hiệu suất, hiểu nó.
Để thực hiện tôi đã tạo ra một phương pháp mà làm như sau:
- Nhận một BufferedImage.
- Lấy WritableRaster của BufferedImage.
- Sử dụng setSample và getSample, xử lý và thay đổi pixel theo pixel.
- Trả về BufferedImage.
Sau đó, tôi sử dụng Bộ hẹn giờ để gọi phương thức. BufferedImage được trả về được gắn vào JButton thông qua setIcon sau mỗi cuộc gọi.
Với hình ảnh 500x500, máy của tôi mất khoảng 3ms để xử lý từng cuộc gọi. Đối với các hình ảnh 1080p tiêu chuẩn phải mất khoảng 30ms, tức là khoảng 33 khung hình mỗi giây.
Mục tiêu của tôi là xử lý/tạo ảnh động FullHD ở tốc độ 30 khung hình/giây ... Và tôi sẽ không thể đi theo đường dẫn mà tôi đang theo dõi. Không có trong hầu hết các máy tính.
Tôi đang làm gì sai? Làm thế nào tôi có thể làm cho nó nhanh hơn? Sử dụng getDataBuffer hoặc getPixels thay vì getSample có thể cải thiện nó?
Cảm ơn trước! Và xin lỗi tiếng anh của tôi.
Kết luận từng phần: Nhờ sự giúp đỡ ở đây. Tôi đã thay đổi khái niệm. Thay vì sử dụng getSample và setSample, tôi đã lưu trữ thông tin ARGB pixel của BufferedImage vào một mảng. Vì vậy, tôi xử lý mảng và sao chép tất cả cùng một lúc vào một Raster của BufferedImage khác.
Thời gian xử lý giảm từ 30ms (lấy/đặt mẫu) xuống 1ms. (đo kém, nhưng trong cùng một máy, môi trường và mã).
Dưới đây là một lớp nhỏ tôi được mã hóa để triển khai. Lớp có thể lọc các pixel chỉ dưới mức Độ sáng, các pixel khác trở nên trong suốt (alpha = 0).
Hy vọng người trợ giúp sẽ tìm kiếm giải pháp tương tự trong tương lai. Hãy cảnh giác rằng tôi dưới cấp độ tân binh trong Java, vì vậy mã có thể được sắp xếp/tối ưu hóa kém.
import java.awt.Graphics2D;
import java.awt.image.*;
/**
* @author Psyny
*/
public class ImageAppearFX {
//Essencial Data
BufferedImage imgProcessed;
int[] RAWoriginal;
int[] RAWprocessed;
WritableRaster rbgRasterProcessedW;
//Information about the image
int x,y;
int[] mapBrightness;
public ImageAppearFX(BufferedImage inputIMG) {
//Store Dimensions
x = inputIMG.getWidth();
y = inputIMG.getHeight();
//Convert the input image to INT_ARGB and store it.
this.imgProcessed = new BufferedImage(x, y, BufferedImage.TYPE_INT_ARGB);
Graphics2D canvas = this.imgProcessed.createGraphics();
canvas.drawImage(inputIMG, 0, 0, x, y, null);
canvas.dispose();
//Create an int Array of the pixels informations.
//p.s.: Notice that the image was converted to INT_ARGB
this.RAWoriginal = ((DataBufferInt) this.imgProcessed.getRaster().getDataBuffer()).getData();
//Dupplication of original pixel array. So we can make changes based on original image
this.RAWprocessed = this.RAWoriginal.clone();
//Get Raster. We will need the raster to write pixels on
rbgRasterProcessedW = imgProcessed.getRaster();
//Effect Information: Store brightness information
mapBrightness = new int[x*y];
int r,g,b,a,greaterColor;
// PRocess all pixels
for(int i=0 ; i < this.RAWoriginal.length ; i++) {
a = (this.RAWoriginal[i] >> 24) & 0xFF;
r = (this.RAWoriginal[i] >> 16) & 0xFF;
g = (this.RAWoriginal[i] >> 8) & 0xFF;
b = (this.RAWoriginal[i] ) & 0xFF;
//Search for Stronger Color
greaterColor = r;
if(b > r) {
if(g > b) greaterColor = g;
else greaterColor = b;
} else if (g > r) {
greaterColor = g;
}
this.mapBrightness[i] = greaterColor;
}
}
//Effect: Show only in a certain percent of brightness
public BufferedImage BrightnessLimit(float percent) {
// Adjust input values
percent = percent/100;
// Pixel Variables
int hardCap = (int)(255 * percent);
int r,g,b,a,bright;
// Process all pixels
for(int i=0 ; i < this.RAWoriginal.length ; i++) {
//Get information of a pixel of the ORIGINAL image
a = (this.RAWoriginal[i] >> 24) & 0xFF;
r = (this.RAWoriginal[i] >> 16) & 0xFF;
g = (this.RAWoriginal[i] >> 8) & 0xFF;
b = (this.RAWoriginal[i] ) & 0xFF;
//Brightness information of that same pixel
bright = this.mapBrightness[i];
//
if(bright > hardCap ) {
a = 0;
}
this.RAWprocessed[i] = ((a << 24) + (r << 16) + (g << 8) + (b)); //Write ARGB in byte format
}
//Copy the processed array into the raster of processed image
rbgRasterProcessedW.setDataElements(0, 0, x, y, RAWprocessed);
return imgProcessed;
}
//Return reference to the processed image
public BufferedImage getImage() {
return imgProcessed;
}
}
Bạn không thể đặt vòng lặp 1-4 trong một khoảng thời gian thay vì có tất cả các chi phí của Bộ hẹn giờ? –
Vâng, tôi nghĩ tôi có thể. Tuy nhiên, nó sẽ không cải thiện hiệu suất cho mỗi lần vượt qua, đó là nút cổ chai của tôi. Tôi nghĩ rằng bằng cách nào đó BufferedImage sẽ cố gắng cập nhật nội bộ sau mỗi thay đổi trong kênh raster. Có lẽ tôi cần hoàn toàn soạn dữ liệu hình ảnh mới trước khi vẽ bất kỳ thứ gì lên raster? Tôi không biết làm thế nào ... – Psyny
Có thể có một số tùy chọn. Từ việc lấy trực tiếp pixel dưới dạng mảng (có nhiều khả năng là cách nhanh nhất, nhưng có thể làm giảm hiệu suất của * vẽ * hình ảnh - và yêu cầu bạn biết * loại * của hình ảnh đầu vào), đến các phương pháp cấp cao như song song đơn giản. – Marco13