#java #try-catch #sleep #freeze #bufferedimage
#java #попробуйте-поймайте #сон #замораживание #bufferedimage
Вопрос:
Оригинальный вопрос:
Предполагается, что этот метод постепенно преобразует изображение, отображаемое на JFrame, в другое изображение. Однако, без какого-либо способа замедлить его, кажется, что он просто меняется с одного изображения на новое изображение. Чтобы замедлить его, я вставил Thread.sleep(1000), чтобы изменения не происходили мгновенно. Однако с этой строкой моя программа полностью зависает. Нет сообщения об ошибке, ничего нет. Кто-нибудь может мне помочь? Предложите лучший способ замедлить его или как это можно исправить.
Для пояснения: int k — это количество постепенных шагов в изменении. k = 1 будет мгновенным изменением. Что-то большее было бы постепенными изменениями. int l между тем управляет соотношением отображаемой части каждого изображения.
public void morphImg(int width, int height, BufferedImage morphImage, int k) {
//creates new image from two images of same size
BufferedImage image2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int i = 0; i < width; i ) {
for (int j = 0; j < height; j ) {
//get color from original image
Color c = new Color(image.getRGB(i, j));
//get colors from morph image
Color c2 = new Color(morphImage.getRGB(i, j));
for (int l = 1; l <= k; l ) {
//gets colors at different stages
int r = ((k-l)*c.getRed()/k) (l*c2.getRed()/k);
int g = ((k-l)*c.getGreen()/k) (l*c2.getGreen()/k);
int b = ((k-l)*c.getBlue()/k) (l*c2.getBlue()/k);
Color newColor = new Color(r, g, b);
//set colors of new image to average of the two images
image2.setRGB(i, j, newColor.getRGB());
//display new image
try {
imageLabel.setIcon(new ImageIcon(image2));
Thread.sleep(1000);
}
catch (InterruptedException e){
System.out.println("Exception caught.");
}
}
}
}
//sets modified image as "original" for further manipulation
setImage(image2);
}
ОБНОВЛЕННЫЙ КОД: использование таймера также приводит к зависанию программы…Я не правильно его использую?
public void morphImg(int width, int height, BufferedImage morphImage, int k) {
//creates new image from two images of same size
final BufferedImage image2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int l = 1; l <= k; l ) {
for (int i = 0; i < width; i ) {
for (int j = 0; j < height; j ) {
//get color from original image
Color c = new Color(image.getRGB(i, j));
//get colors from morph image
Color c2 = new Color(morphImage.getRGB(i, j));
//gets colors at different stages
int r = ((k-l)*c.getRed()/k) (l*c2.getRed()/k);
int g = ((k-l)*c.getGreen()/k) (l*c2.getGreen()/k);
int b = ((k-l)*c.getBlue()/k) (l*c2.getBlue()/k);
Color newColor = new Color(r, g, b);
//set colors of new image to average of the two images
image2.setRGB(i, j, newColor.getRGB());
//display new image
imageLabel.setIcon(new ImageIcon(image2));
final Timer t = new Timer(500,null);
t.setInitialDelay(500);
t.start();
}
}
}
//sets modified image as "original" for further manipulation
setImage(image2);
}
Комментарии:
1. Знаете ли вы, что вы спите (ширина * высота * k) секунд в общей сложности? Для изображения размером 256×256 с k, равным 10, выполнение вашего кода займет 7 дней.
Ответ №1:
Никогда не используйте Thread.sleep(), когда код выполняется в потоке отправки событий.
Вместо этого вы должны использовать Swing Timer для планирования вашей анимации.
Смотрите Разделы из руководства по Swing на:
- Параллелизм в Swing
- Как использовать таймеры
Или, если вы не хотите использовать таймер, вы можете использовать SwingWorker (как описано в руководстве по параллелизму), а затем просто опубликовать () изображение после его изменения. Затем вы можете использовать Thread.sleep(), поскольку SwingWorker не выполняется в EDT.
Простой пример таймера:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
public class TimerTime extends JPanel implements ActionListener
{
private JLabel timeLabel;
private int count = 0;
public TimerTime()
{
timeLabel = new JLabel( new Date().toString() );
add( timeLabel );
Timer timer = new Timer(1000, this);
timer.setInitialDelay(1);
timer.start();
}
@Override
public void actionPerformed(ActionEvent e)
{
// Update the time
timeLabel.setText( new Date().toString() );
count ;
// Stop after 10 events have been generated
if (count == 10)
{
Timer timer = (Timer)e.getSource();
timer.stop();
System.out.println( "Timer stopped" );
}
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("TimerTime");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new TimerTime() );
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
}
}
Комментарии:
1. спасибо за совет … Как я мог установить таймер для кратковременной приостановки цикла? Я почти не знаком с таймерами…
2. Вот почему я дал вам ссылку на учебник. Затем вы также можете поискать примеры на форуме или в Интернете.
3. Я пытался использовать таймер, у меня была точно такая же проблема с зависанием … Я не правильно ее реализовал?
4. Это было бы моим предположением. Чтобы использовать таймер, вам нужно будет реструктурировать свой код. У вас никогда не будет цикла. Таймер — это цикл. Таймер будет поддерживать и обновлять переменные l, i, j. Таймер запускается вне вашего кода цикла, а не внутри кода. Начните с простого примера, чтобы понять основы. Как я уже предлагал в своем втором предложении, подход SwingWorker позволит вам поддерживать циклическую структуру и Thread.sleep().
Ответ №2:
Цикл над k должен быть самым внешним циклом. Прямо сейчас вы вызываете Thread.sleep k * width * height раз.
Комментарии:
1. Это правда… Я изменил его. Спасибо за совет. Однако это не решает проблему.
Ответ №3:
Если цель состоит в том, чтобы показать прогрессивную анимацию эффекта морфинга, ниже приведен тестовый код, который я сделал без использования Timer
или Thread.sleep()
, используя последний код морфинга, заданный OP:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JApplet;
import javax.swing.JFrame;
class MorphComponent extends Component {
/**
*
*/
private static final long serialVersionUID = 1L;
private BufferedImage bi;
private URL imageSrc1;
private URL imageSrc2;
public MorphComponent(URL imageSrc1, URL imageSrc2) {
this.imageSrc1 = imageSrc1;
this.imageSrc2 = imageSrc2;
try {
BufferedImage img1 = ImageIO.read(imageSrc1);
//BufferedImage img2 = ImageIO.read(imageSrc2);
int w = img1.getWidth(null);
int h = img1.getHeight(null);
bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.getGraphics();
g.drawImage(img1, 0, 0, null);
} catch (IOException e) {
System.out.println("Image could not be read");
System.exit(1);
}
}
public Dimension getPreferredSize() {
return new Dimension(bi.getWidth(null), bi.getHeight(null));
}
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.white);
g2d.fillRect(0,0, getWidth(), getHeight());
try {
BufferedImage img1 = ImageIO.read(imageSrc1);
BufferedImage img2 = ImageIO.read(imageSrc2);
int w = img1.getWidth(null);
int h = img1.getHeight(null);
bi = morphImg(g, img1, img2, w, h, 10);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private long start = System.currentTimeMillis();
public BufferedImage morphImg(Graphics gp, BufferedImage originalImage, BufferedImage morphImage, int width, int height, int k) {
//creates new image from two images of same size
final BufferedImage image2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int l = 1; l <= k; l ) {
for (int i = 0; i < width; i ) {
for (int j = 0; j < height; j ) {
long elapsed = System.currentTimeMillis() - start;
//get color from original image
Color c = new Color(originalImage.getRGB(i, j));
//get colors from morph image
Color c2 = new Color(morphImage.getRGB(i, j));
//gets colors at different stages
int r = ((k-l)*c.getRed()/k) (l*c2.getRed()/k);
int g = ((k-l)*c.getGreen()/k) (l*c2.getGreen()/k);
int b = ((k-l)*c.getBlue()/k) (l*c2.getBlue()/k);
Color newColor = new Color(r, g, b);
//set colors of new image to average of the two images
image2.setRGB(i, j, newColor.getRGB());
if( elapsed > 100 ) {
gp.drawImage(image2, 0, 0, null);
start = System.currentTimeMillis();
repaint();
}
}
}
}
return image2;
}
}
public class MorphImageApplet extends JApplet {
/**
*
*/
private static final long serialVersionUID = 1L;
static String imageFileName1 = "image_1.jpg";
static String imageFileName2 = "image_2.jpg";
private URL imageSrc1;
private URL imageSrc2;
public MorphImageApplet () {
}
public MorphImageApplet (URL imageSrc1, URL imageSrc2) {
this.imageSrc1 = imageSrc1;
this.imageSrc2 = imageSrc2;
}
public void init() {
try {
imageSrc1 = new URL(getCodeBase(), imageFileName1);
imageSrc2 = new URL(getCodeBase(), imageFileName2);
} catch (MalformedURLException e) {
}
buildUI();
}
public void buildUI() {
final MorphComponent st = new MorphComponent(imageSrc1, imageSrc2);
add("Center", st);
}
public static void main(String s[]) {
JFrame f = new JFrame("See Through Image");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});
URL imageSrc1 = null;
URL imageSrc2 = null;
try {
imageSrc1 = ((new File(imageFileName1)).toURI()).toURL();
imageSrc2 = ((new File(imageFileName2)).toURI()).toURL();
} catch (MalformedURLException e) {
}
MorphImageApplet sta = new MorphImageApplet(imageSrc1, imageSrc2);
sta.buildUI();
f.add("Center", sta);
f.pack();
f.setVisible(true);
}
}