void crossfade() { int[] pixA = startView.getPixels(); int[] pixM = morphView.getPixels(); int[] pixB = endView.getPixels(); int width = morphView.getImgWidth(); int height = morphView.getImgHeight(); double a = morphPos; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int posM = y * width + x; int argb = pixA[posM]; int rA = (argb >> 16) & 0xff; int gA = (argb >> 8) & 0xff; int bA = (argb) & 0xff; argb = pixB[posM]; int rB = (argb >> 16) & 0xff; int gB = (argb >> 8) & 0xff; int bB = (argb) & 0xff; int rM = (int) ((1 - a) * rA + a * rB); int gM = (int) ((1 - a) * gA + a * gB); int bM = (int) ((1 - a) * bA + a * bB); pixM[posM] = 0xFF000000 | (rM << 16) | (gM << 8) | bM; } } }
private synchronized void calculate() { long startTime = System.currentTimeMillis(); switch (method.getSelectedIndex()) { case 0: crossfade(); break; case 1: scaleLeft(); break; // TODO: add the other methods here default: Arrays.fill(morphView.getPixels(), 0xffffffff); // white image break; } morphView.applyChanges(); long time = System.currentTimeMillis() - startTime; statusLine.setText("Processing time: " + time + " ms"); }
void scaleLeft() { // This implements a simple nearest neighbor scaling. // You may replace it by a bilinear scaling for better visual results int[] pixA = startView.getPixels(); int[] pixM = morphView.getPixels(); int width = morphView.getImgWidth(); int height = morphView.getImgHeight(); double a = morphPos; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int posM = y * width + x; // current scaling double xS = scalingX * a + 1.0 * (1 - a); double yS = scalingY * a + 1.0 * (1 - a); // scaled coordinates in image A int xA = (int) (x * xS); int yA = (int) (y * yS); int argb = 0xffffffff; // white pixel if (xA >= 0 && xA < width && yA >= 0 && yA < height) { // we are inside image A argb = pixA[yA * width + xA]; } int rM = (argb >> 16) & 0xff; int gM = (argb >> 8) & 0xff; int bM = (argb) & 0xff; pixM[posM] = 0xFF000000 | (rM << 16) | (gM << 8) | bM; } } }
public Morph() { super(new BorderLayout(borderWidth, borderWidth)); setBorder(BorderFactory.createEmptyBorder(borderWidth, borderWidth, borderWidth, borderWidth)); // load the default images File input1 = new File("RedApple.jpg"); if (!input1.canRead()) input1 = openFile("Open Image 1"); // file not found, choose another image File input2 = new File("GreenApple.jpg"); if (!input2.canRead()) input2 = openFile("Open Image 2"); // file not found, choose another image startView = new ImageView(input1); startView.setMaxSize(new Dimension(maxWidth, maxHeight)); endView = new ImageView(input2); endView.setMaxSize(new Dimension(maxWidth, maxHeight)); // create empty image for morphing morphView = new ImageView(startView.getImgWidth(), startView.getImgHeight()); morphView.setMaxSize(new Dimension(maxWidth, maxHeight)); // control panel JPanel controls = new JPanel(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.insets = new Insets(0, borderWidth, 0, 0); // transmission methods String[] methodNames = { "Cross-fading", "Scale left image", "Scale right image", "Scale & move left image", "Scale & move right image", "Morphing" }; method = new JComboBox<String>(methodNames); method.setSelectedIndex(0); // set initial method method.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { calculate(); } }); // morphing position JLabel morphLabel = new JLabel("Morphing Position:"); morphPos = 0; morphSlider = new JSlider(JSlider.HORIZONTAL, 0, sliderGranularity, (int) (morphPos * sliderGranularity)); morphSlider.addChangeListener( new ChangeListener() { public void stateChanged(ChangeEvent e) { morphPos = morphSlider.getValue() / (double) sliderGranularity; calculate(); } }); controls.add(method, c); controls.add(morphLabel, c); controls.add(morphSlider, c); // images JPanel images = new JPanel(new GridLayout(1, 3)); images.add(startView); images.add(morphView); images.add(endView); // status panel JPanel status = new JPanel(new GridLayout(1, 3)); // some status text statusLine = new JLabel(" "); status.add(statusLine, c); add(controls, BorderLayout.NORTH); add(images, BorderLayout.CENTER); add(status, BorderLayout.SOUTH); calculate(); }