2016-04-23 2 views
2

У меня есть вопрос относительно того, как вырезать пустое место на изображении (или просто нацарапать его). Я хочу, чтобы иметь метод, как это:Удалить пустое место на изображении JAVA

public BufferedImage crop(BufferedImage input) { 
    return output; 
} 

И он должен сделать это:

http://i.stack.imgur.com/IGTRS.png

Я знаю, что я мог бы пройти через все пиксели, чтобы получить новые границы, но для exapmle с image 1024x768 Мне нужно было бы пройти через 1024 * 768 = 786432 (раз 2, потому что я должен пройти первый раз, чтобы получить высоты и второй раз, чтобы получить ширину). И это не очень хорошо. Есть ли идеи, как это сделать быстро? (Я не хочу использовать neihter любые дополнительные потоки и любые дополнительные рамки, если это возможно)

Спасибо!

+2

компьютеров быстро, это не займет много времени, чтобы пройти через все пиксели в 1024 х 768 пикселях изображения. Кроме того, есть более разумные способы сделать это, чем сканировать все пиксели дважды - вы должны сканировать только до тех пор, пока не найдете не белый пиксель, и вам не нужно делать это отдельно для горизонтальной и вертикальной. – Jesper

ответ

2

Я много думал и придумал этот метод, как это сделать.

public static BufferedImage crop(BufferedImage image) { 
    int minY = 0, maxY = 0, minX = Integer.MAX_VALUE, maxX = 0; 
    boolean isBlank, minYIsDefined = false; 
    Raster raster = image.getRaster(); 

    for (int y = 0; y < image.getHeight(); y++) { 
     isBlank = true; 

     for (int x = 0; x < image.getWidth(); x++) { 
      //Change condition to (raster.getSample(x, y, 3) != 0) 
      //for better performance 
      if (raster.getPixel(x, y, (int[]) null)[3] != 0) { 
       isBlank = false; 

       if (x < minX) minX = x; 
       if (x > maxX) maxX = x; 
      } 
     } 

     if (!isBlank) { 
      if (!minYIsDefined) { 
       minY = y; 
       minYIsDefined = true; 
      } else { 
       if (y > maxY) maxY = y; 
      } 
     } 
    } 

    return image.getSubimage(minX, minY, maxX - minX + 1, maxY - minY + 1); 
} 

Этот метод работает только с альфой. Для работы с «JPG» Вы должны изменить условия здесь (правда, в данном случае означает, что текущий пиксель не является пустым):

if (raster.getPixel(x, y, (int[]) null)[3] != 0) 

Я был surpirsed, но этот метод работает очень быстро (обрезать 1024x768 изображение его Наталья принимает 70 -100 миллисекунд). Также я протестировал его на изображении 5000x5000 и, к сожалению, этот метод был очень медленным в этом случае (1000-1500 миллисекунд).

Он делит изображение на вертикальные линии для каждой координаты y. Затем он ищет непустую пиксель в этой строке. Если пустой пиксель не был найден, он переходит к следующей строке, но если он был найден, он ищет minX и maxX. Кроме того, если minY еще не определен, он определяет его, а bool «minYIsDefined» делает true. Но если значение minY уже определено, оно определяет maxY.

EDIT:

Как было предложено в коментарии (ТНХ FiReTiTi), с использованием метода 'getSample()' мы можем пойти еще быстрее. Это потому, что метод getPixel() 'использует метод getSample(), чтобы сделать его массив 3-4 раза (зависит от типа изображения). Таким образом, новое состояние будет lõoke так:

if (raster.getSample(x, y, 3) != 0) 

Мои тесты показали, что время, которое было принято для croping 1024x768 изображение было 10-30 мс. В случаях с 5000x5000 время изображения составляло 100-300 мс.

Надеется, что это поможет кому-то :)

+1

Вы используете еще быстрее, используя getSample() вместо getPixel, и даже быстрее, используя DataBuffer (прямой доступ к пикселям). Будьте осторожны, image.getSubimage возвращает вспомогательное изображение с тем же растром, поэтому, если вы его измените, вы также измените исходный. – FiReTiTi

+0

@FiReTiTi «Будьте осторожны, image.getSubimage возвращает вспомогательное изображение с тем же растром, поэтому, если вы его измените, вы также измените исходный». Так как я могу предотвратить это? Скопировать растровый файл и создать новый экземпляр изображения? Не повлияет ли это на скорость? –

+0

@FiReTiTi только что проверил его. Растровое изображение субстрата - это копия оригинального растра. Raster.createWritableChild() создает новый объект. –

Смежные вопросы