2015-07-15 18 views
6

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:

  1. Nhận một BufferedImage.
  2. Lấy WritableRaster của BufferedImage.
  3. Sử dụng setSample và getSample, xử lý và thay đổi pixel theo pixel.
  4. 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; 
    } 
} 
+0

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ờ? –

+2

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

+0

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

Trả lời

1

Mặc dù chênh lệch thời gian do thay đổi không chứng minh rằng việc tìm kiếm lặp lại là nút cổ chai, nhưng nó vẫn mạnh mẽ.

Nếu bạn sẵn sàng/có thể trao đổi bộ nhớ theo thời gian, trước tiên tôi sẽ sắp xếp danh sách tất cả các vị trí pixel theo độ sáng. Tiếp theo, tôi sẽ sử dụng danh sách được sắp xếp trong khi hoạt ảnh để tra cứu pixel tiếp theo cần sao chép.

Một lời khuyên bổ sung: sử dụng một trong các phương pháp sắp xếp được tích hợp sẵn của Java. Đó là giáo dục để làm cho riêng bạn, nhưng học cách sắp xếp dường như không phải là mục tiêu của bạn ở đây. Ngoài ra, nếu tôi đoán về nút cổ chai là sai, bạn sẽ muốn giảm thiểu thời gian của bạn theo đuổi câu trả lời này.

+2

Hum .. Ánh xạ và sắp xếp pixel theo Độ sáng thực sự có thể tránh sự cần thiết phải đi qua tất cả các pixel. Tôi sẽ cố gắng thực hiện nó sớm. – Psyny

Các vấn đề liên quan