2010-01-27 33 views
5

Tôi tự hỏi liệu có cách "thông minh" tách hình ảnh dựa trên các tính năng nhất định không.Cách tách hình ảnh thành hai với java

Hình ảnh có kích thước 300x57, đen trắng (màu xám hoặc trắng), bao gồm hai tính năng chính (hãy gọi chúng là các đốm màu) được phân tách bằng khoảng trắng, mỗi đốm hơi hơi khác nhau về chiều rộng và chiều cao, vị trí của các đốm màu cũng thay đổi, các đốm màu KHÔNG BAO GIỜ trùng lặp!

Đây là những gì một hình ảnh "có vẻ" như:

------------------------- 
----WWW---------WWWWW---- 
---WWWWWWW----WWWWWW----- 
-----WWWW-------WWW------ 
------------------------- 

Việc phân chia kết quả sẽ là một cái gì đó như thế này:

------------  ------------- 
----WWW-----  ----WWWWW---- 
---WWWWWWW--  --WWWWWW----- 
-----WWWW---  ----WWW------ 
------------  ------------- 

bước tôi có kế hoạch đi qua để chia hình ảnh:

  1. Quét hình ảnh từ bên này sang bên kia.
  2. Xác định các cạnh của các đốm màu.
  3. Lấy khoảng cách giữa hai cạnh bên trong.
  4. Tách hình ảnh ở giữa khoảng cách bên trong.
  5. Lưu hai hình ảnh dưới dạng các tệp riêng biệt.

Sẽ tốt hơn nếu tôi chuẩn hóa độ rộng hình ảnh, vì vậy tất cả hình ảnh của tôi đều có chiều rộng đồng đều khi chúng được lưu.

Tôi không có kinh nghiệm về thao tác hình ảnh, vì vậy tôi không biết cách hiệu quả để thực hiện việc này là gì. Tôi hiện đang sử dụng BufferedImage, nhận chiều rộng/chiều cao, lặp lại trên mỗi pixel, v.v. Không có giải pháp nào cho vấn đề của tôi, nhưng tôi đang tìm một giải pháp hiệu quả hơn (ít mã hơn + nhanh hơn). Tôi cũng đã xem xét java.awt.Graphics ...

Tôi sẽ đánh giá cao nếu tôi nhận được một số ý tưởng cho các cách hiệu quả hơn để thực hiện tác vụ này. Tôi muốn gắn bó với các thư viện tích hợp của Java, vì vậy BufferedImage hoặc Graphics2D là thứ hiệu quả nhất để sử dụng trong trường hợp này?

EDIT: Đây là đoạn mã sau khi đọc những gợi ý:

public void splitAndSaveImage(BufferedImage image) throws IOException 
{ 
    // Process image ------------------------------------------   
    int height = image.getHeight(); 
    int width = image.getWidth(); 
    boolean edgeDetected = false; 
    double averageColor = 0; 
    int threshold = -10; 
    int rightEdge = 0; 
    int leftEdge = 0; 
    int middle = 0; 

    // Scan the image and determine the edges of the blobs. 
    for(int w = 0; w < width; ++w) 
    {    
     for(int h = 0; h < height; ++h) 
     { 
      averageColor += image.getRGB(w, h); 
     } 

     averageColor = Math.round(averageColor/(double)height); 

     if(averageColor /*!=-1*/< threshold && !edgeDetected) 
     { 
      // Detected the beginning of the right blob 
      edgeDetected = true; 
      rightEdge = w; 
     }else if(averageColor >= threshold && edgeDetected) 
     { 
      // Detected the end of the left blob 
      edgeDetected = false; 
      leftEdge = leftEdge==0? w:leftEdge; 
     } 

     averageColor = 0; 
    } 

    // Split the image at the middle of the inside distance. 
    middle = (leftEdge + rightEdge)/2; 

    // Crop the image 
    BufferedImage leftImage = image.getSubimage(0, 0, middle, height); 

    BufferedImage rightImage = image.getSubimage(middle, 0, (width-middle), height); 

    // Save the image 
    // Save to file ------------------------------------------- 
    ImageIO.write(leftImage, "jpeg", new File("leftImage.jpeg")); 

    ImageIO.write(rightImage, "jpeg", new File("rightImage.jpeg")); 
} 
+0

Lưu ý: sau khi phát hiện cạnh phải, bạn có thể dễ dàng thoát ra khỏi vòng lặp for. – Kiril

Trả lời

5

Cách đơn giản để thực hiện việc này là tổng các giá trị pixel trong mỗi cột (đi xuống) để tạo một mảng đơn (cùng chiều rộng với hình ảnh đầu vào) của các giá trị trung bình. Bắt đầu ở giữa mảng, tìm kiếm giá trị nhỏ nhất. Đây sẽ là cột nơi bạn có thể chia hình ảnh.

Cột này có thể sẽ không phải là trung tâm của khoảng cách giữa các đốm màu của bạn. Bạn có thể thực hiện một tìm kiếm bên ngoài khác từ cột này, đi bên trái trước tiên để tìm tất cả các cột tương tự và sau đó chuyển sang phải.

------------------------- 
----WWW---------WWWWW---- 
---WWWWWWW----WWWWWW----- 
-----WWWW-------WWW------ 
------------------------- 

col trung bình:

---wwWWwww-----wWWWWww--- 

Tùy thuộc vào cách trống không gian (pixel giá trị khôn ngoan) giữa hai đốm màu, bạn có thể thiết lập giá trị ngưỡng của bạn khá thấp. Nếu có một số tiếng ồn, nó sẽ phải cao hơn một chút.

Tìm giá trị ngưỡng phù hợp có thể là công việc vặt, trừ khi bạn có thể xác định thuật toán theo thuật toán.

+0

+1: Tôi nghĩ điều này sẽ hoạt động rất tốt và rất đơn giản. –

+0

Yah, đó là những gì tôi đã làm. Tôi sẽ đăng mã để người khác xem. – Kiril

1

Tôi không biết của một edge detectionalgorithm mà không yêu cầu lặp lại qua các điểm ảnh, vì vậy cách tiếp cận hiện tại của bạn có thể được tối ưu. Tùy thuộc vào các yếu tố khác, bạn có thể tận dụng ImageJ, trong đó có một bộ sưu tập rộng lớn của analytical plugins.

Phụ lục: Được ưu tiên tránh phụ thuộc bên ngoài, BufferedImage là lựa chọn tốt. Sau khi bạn xác định các cạnh, phương pháp getSubimage() thuận tiện. Bạn có thể sử dụng một trong các phương pháp RastergetPixels() hiệu quả trong chập chững. ImageIO có thể ghi kết quả.

+0

@trashgod Điểm tốt ... Vậy BufferedImage và Graphics2D là những điều tốt nhất để sử dụng trong thư viện java (Tôi không muốn đi ra ngoài)? – Kiril

+0

Có; Tôi đã thêm một số chi tiết ở trên. – trashgod

1

Tôi không nghĩ có bất kỳ lý do gì để làm bất cứ điều gì khác ngoài việc quét từng dòng và dừng lại khi bạn nhận được chuyển đổi trắng -> đen - trắng (không cần quét toàn bộ dòng!). Nếu bạn có thể đoán được vị trí của các đốm màu, có thể có thể tinh chỉnh nó một chút bằng cách chọn điểm bắt đầu ở giữa hình ảnh và sau đó tìm kiếm trái và phải từ đó. Nhưng tôi nghiêm túc nghi ngờ nó sẽ là giá trị nỗ lực.

Ngoài ra, không cần chạy thuật toán phát hiện cạnh đầu tiên trên hình ảnh. Chỉ cần quét các dòng!

EDIT: Ông Berna đã chỉ ra rằng điều này sẽ không hoạt động với các đối tượng lõm.

+0

Điều này xảy ra khi blob bị lõm. Nếu đỉnh của đốm màu có hình dạng như ngón tay, bạn có thể nhận được chuyển đổi màu trắng -> đen -> trắng mà không tìm thấy cạnh của đốm màu đầu tiên. –

+0

@Mr. Berna: Đúng vậy. Nó sẽ chỉ hoạt động (đáng tin cậy) cho các đốm màu lồi. –

1

Khoảng cách giữa các đốm màu có quan trọng không? Nếu bạn không cần phải cân bằng không gian màu trắng, ít công việc sẽ là cần thiết để chỉ tìm thấy một đường thẳng đứng màu trắng giữa các đốm màu. Kiểm tra xem đường thẳng đứng của trung tâm chỉ có các pixel màu trắng hay không. Nếu đường giữa có pixel đen, quét trái và phải cho dòng đầu tiên chỉ có pixel trắng. Để kiểm tra các tình huống mà cả hai đốm màu ở một bên của tâm, quét một đường ngang cho các khoảng trắng đen-đen. Nếu đường thẳng đứng được chọn nằm trong khoảng trắng được bao quanh bởi khoảng màu đen, bạn sẽ biết có ít nhất một đốm màu ở mỗi bên của phần tách hình ảnh.

Không thực hiện các kiểm tra này sẽ yêu cầu quét các dòng bổ sung, nhưng đối với tất cả hình ảnh được tạo tốt, trong đó các đốm màu nằm ở nửa bên phải và bên trái của hình ảnh, phương pháp này sẽ chỉ quét hai dòng. Phương pháp này có thể mất nhiều thời gian hơn cho các hình ảnh khác hoặc thậm chí là vỡ, đối với các hình ảnh vỏ cạnh. Điều này sẽ vi phạm ví dụ này:

------------------------- 
----WWW----WWWWWWWWWW---- 
---WWWWWWW----WWWWWW----- 
-----WWWWWWWW---WWW------ 
------------------------- 

Nhưng câu hỏi dường như chỉ ra tình huống này là không thể. Nếu lý do đằng sau việc tách hình ảnh này yêu cầu phải xử lý mọi hình ảnh, bạn sẽ cần phương thức thu gọn. Bạn sẽ không cần phương thức thu hồi nếu các trường hợp cạnh có thể bị từ chối. Sau khi quét tìm thấy hình ảnh nằm ngoài phạm vi chấp nhận được, bạn có thể ngừng kiểm tra hình ảnh. Ví dụ: nếu không thể tìm thấy tất cả đường thẳng đứng màu trắng ở trung tâm thứ ba của hình ảnh, bạn có thể từ chối hình ảnh. Hoặc bạn chỉ có thể sử dụng phương pháp này làm tối ưu hóa, chạy kiểm tra này chỉ trên hai dòng để tìm và chia các hình ảnh được tạo tốt, sau đó chuyển các hình ảnh kém thành một thuật toán kỹ lưỡng hơn.

+0

Tôi thích ý tưởng quét đường ngang ... Tôi sẽ thử nghiệm với nó.Trong mẫu 1000+ hình ảnh của tôi, tôi chưa có một hình ảnh mà các phần của hai đốm màu chiếm cùng một đường thẳng đứng, các đốm màu luôn được phân tách bằng một vài đường trắng. – Kiril

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