ImageSelection package
Entry.java
package imageselection;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
import java.util.*;
/**
* Class to enable selection of region to be inpainted
*/
public class Entry extends JPanel {
protected Image entryImage; // Image to be displayed
protected Graphics entryGraphics; // graphics object to the entry image
protected int lastX = -1; // X co-ordinate of last pressed co-ordinate
protected int lastY = -1; // Y co-ordinate of last pressed co-ordinate
protected int polySides = 0; // number of sides of the polygon to be inpainted
private Vector PolygonCoordinatesX; // vector to store X co-ordinate of all vertices of a polygon
private Vector PolygonCoordinatesY; // vector to store Y co-ordinate of all vertices of a polygon
private Image img; // instance of Image class
public Stack SavedImages; // stack used to implement undo option
public Stack RedoImages; // stack used to implement redo option
private int firstX = -1; // variable to store first X co-ordinate of a polygon
private int firstY = -1; // variable to store first Y co-ordinate of a polygon
private int currX = -1; // variable to store current X co-ordinate of a polygon
private int currY = -1; // variable to store current Y co-ordinate of a polygon
public Boolean isDisabled = false; // flag to determine status of the inpainting module
public int maxX = -1; // stores maximum of all X co-ordinates of all polygon
public int maxY = -1; // stores maximum of all Y co-ordinates of all polygon
public int minX = -1; // stores minimum of all X co-ordinates of all polygon
public int minY = -1; // stores minimum of all Y co-ordinates of all polygon
Boolean pressed; // Defines whether the polygon is started or not
/**
* constructor of Entry class
* @param img default image to display
*/
Entry(Image img)
{
entryImage = img;
enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK|
AWTEvent.MOUSE_EVENT_MASK|
AWTEvent.COMPONENT_EVENT_MASK);
pressed = false;
SavedImages = new Stack();
RedoImages = new Stack();
PolygonCoordinatesX = new Vector();
PolygonCoordinatesY = new Vector();
}
/**
* method to show updated image
* @param img image to display
*/
public void showImage(Image img)
{
entryImage = img;
entryGraphics = entryImage.getGraphics();
repaint();
}
/**
* method to get entryimage
* @return entryimage
*/
public Image getImage()
{
return entryImage;
}
@SuppressWarnings("unchecked")
protected void initImage()
{
img = entryImage;
entryGraphics = entryImage.getGraphics();
Image tmg = createImage(entryImage.getWidth(this),entryImage.getHeight(this));
Graphics tg = tmg.getGraphics();
tg.drawImage(entryImage,0,0,null);
SavedImages.push(tmg);
repaint();
}
@Override
public void paint(Graphics g)
{
if ( entryImage==null )
initImage();
g.drawImage(entryImage,0,0,this);
/**
* Draw red rectangle on first selected co-ordinate of a polygon
*/
if (firstX != -1) {
g.setColor(Color.red);
g.drawRect(firstX-5, firstY-5, 10, 10);
g.drawRect(firstX-4, firstY-4, 8, 8);
}
g.setColor(Color.black);
g.drawRect(0,0,getWidth(),getHeight());
g.setColor(Color.green);
if (PolygonCoordinatesX == null || PolygonCoordinatesY == null) {
return;
}
/**
* Draw black rectangle on every other co-ordinate of a polygon except the first co-ordinate
*/
g.setColor(Color.black);
for (int i = 1; i < PolygonCoordinatesX.size(); ++i) {
g.drawRect((Integer)PolygonCoordinatesX.get(i)-5, (Integer)PolygonCoordinatesY.get(i)-5, 10, 10);
g.drawRect((Integer)PolygonCoordinatesX.get(i)-4, (Integer)PolygonCoordinatesY.get(i)-4, 8, 8);
}
g.setColor(Color.green);
if (lastX != -1) {
g.drawLine(lastX, lastY, currX, currY); // draw line between successive co-ordinates
}
}
@Override
@SuppressWarnings("unchecked")
protected void processMouseEvent(MouseEvent e)
{
if (!isDisabled) {
if ( e.getID()==MouseEvent.MOUSE_PRESSED && !pressed) {
lastX = e.getX();
lastY = e.getY();
firstX = lastX;
firstY = lastY;
pressed = true;
PolygonCoordinatesX.add(lastX);
PolygonCoordinatesY.add(lastY);
repaint();
} else if (e.getID() == MouseEvent.MOUSE_PRESSED && pressed) {
entryGraphics.setColor(Color.green);
entryGraphics.drawLine(lastX,lastY,e.getX(),e.getY());
getGraphics().drawImage(entryImage,0,0,this);
repaint();
lastX = e.getX();
lastY = e.getY();
maxX = maxY = -1;
minX = lastX;
minY = lastY;
PolygonCoordinatesX.add(lastX);
PolygonCoordinatesY.add(lastY);
if (Math.abs(lastX - (Integer)PolygonCoordinatesX.get(0)) < 10 && Math.abs(lastY - (Integer)PolygonCoordinatesY.get(0)) < 10) {
int[] PolyX = new int[PolygonCoordinatesX.size()];
int[] PolyY = new int[PolygonCoordinatesY.size()];
for (int i = 0; i < PolygonCoordinatesX.size(); ++i) {
PolyX[i] = (Integer)PolygonCoordinatesX.get(i);
PolyY[i] = (Integer)PolygonCoordinatesY.get(i);
if (minX > PolyX[i]) {
minX = PolyX[i];
}
if (minY > PolyY[i]) {
minY = PolyY[i];
}
if (maxX < PolyX[i]) {
maxX = PolyX[i];
}
if (maxY < PolyY[i]) {
maxY = PolyY[i];
}
System.out.println(PolygonCoordinatesX.get(i) + ", " + PolygonCoordinatesY.get(i));
}
polySides = PolygonCoordinatesX.size();
entryGraphics.fillPolygon(PolyX, PolyY, polySides);
PolygonCoordinatesX.clear();
PolygonCoordinatesY.clear();
currX = currY = -1;
lastX = lastY = -1;
firstX = firstY = -1;
pressed = false;
Image tmg = createImage(entryImage.getWidth(this),entryImage.getHeight(this));
Graphics tg = tmg.getGraphics();
tg.drawImage(entryImage,0,0,null);
//UndoImages.add(tmg);
SavedImages.push(tmg);
RedoImages.clear();
repaint();
}
} else {
return;
}
}
}
@Override
protected void processMouseMotionEvent(MouseEvent e)
{
if (!isDisabled) {
if ( e.getID()!=MouseEvent.MOUSE_MOVED )
return;
currX = e.getX();
currY = e.getY();
repaint();
}
}
void setDisabled()
{
isDisabled = true;
}
void setEnabled()
{
isDisabled = false;
}
public Boolean getPressed() {
return pressed;
}
void entryReset() {
PolygonCoordinatesX.clear();
PolygonCoordinatesY.clear();
currX = currY = -1;
lastX = lastY = -1;
firstX = firstY = -1;
pressed = false;
}
Object entryImage() {
throw new UnsupportedOperationException("Not yet implemented");
}
}
GradientCalculator.java
package imageselection;
import java.util.*;
/**
*
*/
public class GradientCalculator {
public double[][] gradientX; // Variable to communicate the gradient in X direction with calling class
public double[][] gradientY; // Variable to communicate the gradient in X direction with calling class
int r, g, b; // temporary variables to store the r, g and b values of the pixels.
/**
* Function that calculates the gradient from the image given in argument using the central difference method.
* @param pixelmap Pixelmap of the image
* @param ih Height of the image
* @param iw Width of the image
*/
public void calculateGradientFromImage (int pixelmap[][], int ih, int iw)
{
gradientX = new double[ih][iw];
gradientY = new double[ih][iw];
int[] row = new int[ih];
int[] column = new int[iw];
for (int i = 0; i < ih; ++i) {
row[i] = i+1;
}
for (int i = 0; i < iw; ++i) {
column[i] = i+1;
}
double t1, t2, t3;
if (ih > 1) {
/**
* Calculate gradient for boundary pixels.
*/
for (int j = 0; j < iw; ++j) {
extractRGB(pixelmap, 1, j);
int r2 = r; int g2 = g; int b2 = b;
extractRGB(pixelmap, 0, j);
int r1 = r; int g1 = g; int b1 = b;
t1 = (double)(r2-r1)/(row[1]-row[0]);
t2 = (double)(g2-g1)/(row[1]-row[0]);
t3 = (double)(b2-b1)/(row[1]-row[0]);
gradientX[0][j] = -((double)t1+t2+t3)/(3.0*255.0);
extractRGB(pixelmap, ih-1, j);
int rn = r; int gn = g; int bn = b;
extractRGB(pixelmap, ih-2, j);
int rn1 = r; int gn1 = g; int bn1 = b;
t1 = (double)(rn-rn1)/(row[ih-1]-row[ih-2]);
t2 = (double)(gn-gn1)/(row[ih-1]-row[ih-2]);
t3 = (double)(bn-bn1)/(row[ih-1]-row[ih-2]);
gradientX[ih-1][j] = -((double)t1+t2+t3)/(3.0*255.0);
}
}
if (ih > 2) {
/**
* Calculate the gradient for central pixels.
*/
for (int i = 1; i < ih-1; ++i) {
for (int j = 0; j < iw; ++j) {
extractRGB(pixelmap, i+1, j);
int r2 = r; int g2 = g; int b2 = b;
extractRGB(pixelmap, i-1, j);
int r1 = r; int g1 = g; int b1 = b;
t1 = (double)(r2-r1)/(row[i+1]-row[i-1]);
t2 = (double)(g2-g1)/(row[i+1]-row[i-1]);
t3 = (double)(b2-b1)/(row[i+1]-row[i-1]);
gradientX[i][j] = -((double)t1+t2+t3)/(3.0*255.0);
}
}
}
if (iw > 1) {
/**
* Calculate gradient for boundary pixels.
*/
for (int j = 0; j < ih; ++j) {
extractRGB(pixelmap, j, 1);
int r2 = r; int g2 = g; int b2 = b;
extractRGB(pixelmap, j, 0);
int r1 = r; int g1 = g; int b1 = b;
t1 = (double)(r2-r1)/(column[1]-column[0]);
t2 = (double)(g2-g1)/(column[1]-column[0]);
t3 = (double)(b2-b1)/(column[1]-column[0]);
gradientY[j][0] = (double)(t1+t2+t3)/(3.0*255.0);
extractRGB(pixelmap, j, iw-1);
int rn = r; int gn = g; int bn = b;
extractRGB(pixelmap, j, iw-2);
int rn1 = r; int gn1 = g; int bn1 = b;
t1 = (double)(rn-rn1)/(column[iw-1]-column[iw-2]);
t2 = (double)(gn-gn1)/(column[iw-1]-column[iw-2]);
t3 = (double)(bn-bn1)/(column[iw-1]-column[iw-2]);
gradientY[j][iw-1] = (double)(t1+t2+t3)/(3.0*255.0);
}
}
if (iw > 2) {
/**
* Calculate gradient for central pixels.
*/
for (int i = 0; i < ih; ++i) {
for (int j = 1; j < iw-1; ++j) {
extractRGB(pixelmap, i, j+1);
int r2 = r; int g2 = g; int b2 = b;
extractRGB(pixelmap, i, j-1);
int r1 = r; int g1 = g; int b1 = b;
t1 = (double)(r2-r1)/(column[j+1]-column[j-1]);//g(2:n-1,:) = (f(3:n,:)-f(1:n-2,:))./h(:,ones(p,1));
t2 = (double)(g2-g1)/(column[j+1]-column[j-1]);
t3 = (double)(b2-b1)/(column[j+1]-column[j-1]);
gradientY[i][j] = (double)(t1+t2+t3)/(3.0*255.0);
}
}
}
}
/**
* Function to calculate gradient for other matrices
* @param a The matrix for which gradient is to be calculated
* @param ih Height of the matrix
* @param iw Width of the matrix
*/
public void calculateGradient (int a[][], int ih, int iw)
{
gradientX = new double[ih][iw];
gradientY = new double[ih][iw];
Vector h = new Vector();
int[] row = new int[ih];
int[] column = new int[iw];
for (int i = 0; i < ih; ++i) {
row[i] = i+1;
}
for (int i = 0; i < iw; ++i) {
column[i] = i+1;
}
if (ih > 1) {
for (int j = 0; j < iw; ++j) {
gradientY[0][j] = (double)(a[1][j] - a[0][j])/(row[1]-row[0]);
gradientY[ih-1][j] = (double)(a[ih-1][j] - a[ih-2][j])/(row[ih-1]-row[ih-2]);
}
}
if (ih > 2) {
for (int i = 1; i < ih-1; ++i) {
for (int j = 0; j < iw; ++j) {
gradientY[i][j] = (double)(a[i+1][j] - a[i-1][j])/(row[i+1]-row[i-1]);
}
}
}
if (iw > 1) {
for (int j = 0; j < ih; ++j) {
gradientX[j][0] = (double)(a[j][1] - a[j][0])/(column[1]-column[0]);
gradientX[j][iw-1] = (double)(a[j][iw-1] - a[j][iw-2])/(column[iw-1]-column[iw-2]);
}
}
if (iw > 2) {
for (int i = 0; i < ih; ++i) {
for (int j = 1; j < iw-1; ++j) {
gradientX[i][j] = (double)(a[i][j+1] - a[i][j-1])/(column[j+1]-column[j-1]);
}
}
}
}
/**
* Function to calculate RGB values of the pixel
* @param img
* @param i
* @param j
*/
void extractRGB(int img[][], int i, int j)
{
r = 0xff & (img[i][j] >> 16);
g = 0xff & (img[i][j] >> 8);
b = 0xff & (img[i][j]);
}
}
Main.java
package imageselection;
import com.permission.Display;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.UIManager;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.image.*;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import inpaint.*;
/**
* Class to make UI and communicate the ImageInpainting module
* @author Pulkit & Sapan
*/
public class Main extends JFrame implements Runnable{
public Entry entry; // Defines the object of Entry class
protected Image entryImage; // variable of type Image
JScrollPane pictureScrollPane; // Scrollpane for scrolling Images(whenever required)
File outputFile; // file used while saving the image
String fileExtension; // string to store the extension of a image
ImageInpaint Inpainter; // Defines the object of ImageInpaint class
Thread inpaintThread = null; // thread for the inpaint process
private Boolean fastInpaint = false; // flag to determine fastInpaint
//Button playbtn;
private javax.swing.JButton jButton1;
private javax.swing.JButton jButton2;
private javax.swing.JButton jButton3;
private javax.swing.JButton jButton4;
private javax.swing.JButton jButton6;
private javax.swing.JButton jButton7;
private javax.swing.JFrame jFrame5;
private javax.swing.JFrame jFrame6;
private javax.swing.JFrame jFrame7;
private javax.swing.JToolBar jToolBar1;
@SuppressWarnings("deprecation")
Main()
{
Inpainter = new ImageInpaint(this); // Creates an instance of the ImageInpaint class
/**
* sets look and feel for the UI
*/
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
/**
* Action to be performed on clicking the close button
*/
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
initComponents();
/**
* Reads the image to be inpainted.
*/
try {
entryImage = ImageIO.read(getClass().getResource("/imageselection/Images/defaultImage.png"));
} catch (IOException ex) {
Logger.getLogger(Entry.class.getName()).log(Level.SEVERE, null, ex);
}
setTitle("Image Inpainting"); // Set the title of the Window
getContentPane().setLayout(null);
setSize(500,500); //Set Window Width and Height
entry = new Entry(entryImage); // creates an instance of the entry class
entry.setPreferredSize(new Dimension(entryImage.getWidth(this),entryImage.getHeight(this)));
getContentPane().add(entry);
entry.initImage();
pictureScrollPane = new JScrollPane(); // creates an instance of the JScrollPane class
getContentPane().add(pictureScrollPane);
int w = Math.min(entryImage.getWidth(this)+3,getContentPane().getWidth());
int h = Math.min(entryImage.getHeight(this)+3,getContentPane().getHeight()-50);
if (h == entryImage.getHeight(this)+3) {
pictureScrollPane.setBounds((getContentPane().getWidth()-w)/2,(getContentPane().getHeight()-h)/2, w, h);
} else {
pictureScrollPane.setBounds((getContentPane().getWidth()-w)/2,(getContentPane().getHeight()-h)/2, w, h+25);
}
pictureScrollPane.setAlignmentY(CENTER_ALIGNMENT);
pictureScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
pictureScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
pictureScrollPane.setViewportView(entry);
this.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
int w = Math.min(entryImage.getWidth(entry)+3,getContentPane().getWidth());
int h = Math.min(entryImage.getHeight(entry)+3,getContentPane().getHeight()-50);
if (h == entryImage.getHeight(entry)+3) {
pictureScrollPane.setBounds((getContentPane().getWidth()-w)/2,(getContentPane().getHeight()-h)/2, w, h);
} else {
pictureScrollPane.setBounds((getContentPane().getWidth()-w)/2,(getContentPane().getHeight()-h)/2, w, h+25);
}
// pictureScrollPane.setBounds((getContentPane().getWidth()-w)/2,(getContentPane().getHeight()-h)/2, w, h);
pictureScrollPane.setViewportView(entry);
}
});
}
/**
* main function execution starts from here
* @param args command line argument
*/
@SuppressWarnings("deprecation")
public static void main(String[] args) {
(new Main()).show();
}
private void initComponents() {
JFrame jFrame1 = new javax.swing.JFrame();
JFrame jFrame2 = new javax.swing.JFrame();
JFrame jFrame3 = new javax.swing.JFrame();
JFrame jFrame4 = new javax.swing.JFrame();
JMenuBar jMenuBar1 = new javax.swing.JMenuBar();
JMenu jMenu1 = new javax.swing.JMenu();
JMenu jMenu2 = new javax.swing.JMenu();
JMenu jMenu3 = new javax.swing.JMenu();
JMenu jMenu4 = new javax.swing.JMenu();
JMenuItem jMenuItem1 = new javax.swing.JMenuItem();
JMenuItem jMenuItem2 = new javax.swing.JMenuItem();
JMenuItem jMenuItem3 = new javax.swing.JMenuItem();
JMenuItem jMenuItem4 = new javax.swing.JMenuItem();
JMenuItem jMenuItem5 = new javax.swing.JMenuItem();
JMenuItem jMenuItem6 = new javax.swing.JMenuItem();
JMenuItem jMenuItem7 = new javax.swing.JMenuItem();
JMenuItem jMenuItem8 = new javax.swing.JMenuItem();
JMenuItem jMenuItem9 = new javax.swing.JMenuItem();
javax.swing.GroupLayout jFrame1Layout = new javax.swing.GroupLayout(jFrame1.getContentPane());
jFrame1.getContentPane().setLayout(jFrame1Layout);
jFrame1Layout.setHorizontalGroup(
jFrame1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
jFrame1Layout.setVerticalGroup(
jFrame1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
javax.swing.GroupLayout jFrame2Layout = new javax.swing.GroupLayout(jFrame2.getContentPane());
jFrame2.getContentPane().setLayout(jFrame2Layout);
jFrame2Layout.setHorizontalGroup(
jFrame2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
jFrame2Layout.setVerticalGroup(
jFrame2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
javax.swing.GroupLayout jFrame3Layout = new javax.swing.GroupLayout(jFrame3.getContentPane());
jFrame3.getContentPane().setLayout(jFrame3Layout);
jFrame3Layout.setHorizontalGroup(
jFrame3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
jFrame3Layout.setVerticalGroup(
jFrame3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
javax.swing.GroupLayout jFrame4Layout = new javax.swing.GroupLayout(jFrame3.getContentPane());
jFrame4.getContentPane().setLayout(jFrame4Layout);
jFrame4Layout.setHorizontalGroup(
jFrame4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
jFrame4Layout.setVerticalGroup(
jFrame4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jMenu1.setText("File");
jMenuItem1.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
jMenuItem1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imageselection/Images/open.png")));
jMenuItem1.setText("Open Image");
jMenu1.add(jMenuItem1);
jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jMenuItem1ActionPerformed(evt);
}
});
jMenuItem2.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK));
jMenuItem2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imageselection/Images/save.png")));
jMenuItem2.setText("Save");
jMenu1.add(jMenuItem2);
jMenuItem2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jMenuItem2ActionPerformed(evt);
}
});
jMenuItem7.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.ALT_MASK | java.awt.event.InputEvent.CTRL_MASK));
jMenuItem7.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imageselection/Images/saveAs.png")));
jMenuItem7.setText("Save As");
jMenu1.add(jMenuItem7);
jMenuItem7.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jMenuItem7ActionPerformed(evt);
}
});
jMenuItem3.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F4, java.awt.event.InputEvent.ALT_MASK));
jMenuItem3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imageselection/Images/exit.png")));
jMenuItem3.setText("Exit");
jMenu1.add(jMenuItem3);
jMenuItem3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jMenuItem3ActionPerformed(evt);
}
});
jMenuBar1.add(jMenu1);
jMenu2.setText("Edit");
jMenuItem4.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Z, java.awt.event.InputEvent.CTRL_MASK));
jMenuItem4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imageselection/Images/undo.png")));
jMenuItem4.setText("Undo");
jMenu2.add(jMenuItem4);
jMenuItem4.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jMenuItem4ActionPerformed(evt);
}
});
jMenuItem5.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Y, java.awt.event.InputEvent.CTRL_MASK));
jMenuItem5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imageselection/Images/redo.png")));
jMenuItem5.setText("Redo");
jMenu2.add(jMenuItem5);
jMenuItem5.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jMenuItem5ActionPerformed(evt);
}
});
jMenuBar1.add(jMenu2);
jMenu3.setText("Inpaint");
jMenuItem8.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_R, java.awt.event.InputEvent.CTRL_MASK));
//jMenuItem8.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imageselection/Images/open.png")));
jMenuItem8.setText("Run");
jMenu3.add(jMenuItem8);
jMenuItem8.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jMenuItem8ActionPerformed(evt);
}
});
jMenu4.setText("Help");
jMenuBar1.add(jMenu3);
jMenuBar1.add(jMenu4);
setJMenuBar(jMenuBar1);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 279, Short.MAX_VALUE)
);
jFrame5 = new javax.swing.JFrame();
jFrame6 = new javax.swing.JFrame();
jFrame7 = new javax.swing.JFrame();
jToolBar1 = new javax.swing.JToolBar();
jButton1 = new javax.swing.JButton();
jButton2 = new javax.swing.JButton();
jButton3 = new javax.swing.JButton();
jButton4 = new javax.swing.JButton();
jButton6 = new javax.swing.JButton();
jButton7 = new javax.swing.JButton();
javax.swing.GroupLayout jFrame5Layout = new javax.swing.GroupLayout(jFrame5.getContentPane());
jFrame5.getContentPane().setLayout(jFrame5Layout);
jFrame5Layout.setHorizontalGroup(
jFrame5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
jFrame5Layout.setVerticalGroup(
jFrame5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
javax.swing.GroupLayout jFrame6Layout = new javax.swing.GroupLayout(jFrame6.getContentPane());
jFrame6.getContentPane().setLayout(jFrame6Layout);
jFrame6Layout.setHorizontalGroup(
jFrame6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
jFrame6Layout.setVerticalGroup(
jFrame6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
javax.swing.GroupLayout jFrame7Layout = new javax.swing.GroupLayout(jFrame7.getContentPane());
jFrame7.getContentPane().setLayout(jFrame7Layout);
jFrame7Layout.setHorizontalGroup(
jFrame7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
jFrame7Layout.setVerticalGroup(
jFrame7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jToolBar1.setRollover(true);
jButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imageselection/Images/open.png"))); // NOI18N
jButton1.setFocusable(false);
jButton1.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
jButton1.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
jToolBar1.add(jButton1);
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jMenuItem1ActionPerformed(evt);
}
});
jButton2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imageselection/Images/save.png"))); // NOI18N
jButton2.setFocusable(false);
jButton2.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
jButton2.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
jToolBar1.add(jButton2);
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jMenuItem2ActionPerformed(evt);
}
});
jButton3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imageselection/Images/undo.png"))); // NOI18N
jButton3.setFocusable(false);
jButton3.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
jButton3.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
jToolBar1.add(jButton3);
jButton3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jMenuItem4ActionPerformed(evt);
}
});
jButton4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imageselection/Images/redo.png"))); // NOI18N
jButton4.setFocusable(false);
jButton4.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
jButton4.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
jToolBar1.add(jButton4);
jButton4.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jMenuItem5ActionPerformed(evt);
}
});
javax.swing.GroupLayout layout1 = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout1);
layout1.setHorizontalGroup(
layout1.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
);
layout1.setVerticalGroup(
layout1.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout1.createSequentialGroup()
.addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(275, Short.MAX_VALUE))
);
pack();
}
/**
* action performed for opening file
* @param evt
*/
private void jMenuItem1ActionPerformed(ActionEvent evt) {
if (!entry.isDisabled) {
BufferedImage selectedImage;
JFileChooser _fileChooser = new JFileChooser();
int retval = _fileChooser.showOpenDialog(Main.this);
/**
* extensions of images user is allowed to choose
*/
final String[] okFileExtensions = new String[] {"jpg", "png", "gif", "bmp", "jpeg"};
File file;
if (retval == JFileChooser.APPROVE_OPTION) {
try {
file = _fileChooser.getSelectedFile();
Boolean flag = false;
for (String extension : okFileExtensions) {
if (file.getName().toLowerCase().endsWith(extension)) {
outputFile = file;
fileExtension = extension;
flag = true;
}
}
if (!flag) {
JOptionPane.showMessageDialog(this, "Please choose a jpg, jpeg, png, bmp or gif file only.","Error",JOptionPane.ERROR_MESSAGE);
return;
}
entry.SavedImages.clear();
entry.RedoImages.clear();
selectedImage = ImageIO.read(file);
Image tmg = createImage(((Image)selectedImage).getWidth(this),((Image)selectedImage).getHeight(this));
Graphics tg = tmg.getGraphics();
tg.drawImage((Image)selectedImage,0,0,null);
entry.SavedImages.push(selectedImage);
entryImage = tmg;
entry.showImage(entryImage);
entry.setPreferredSize(new Dimension(entryImage.getWidth(this),entryImage.getHeight(this)));
int w = Math.min(entryImage.getWidth(this)+3,getContentPane().getWidth());
int h = Math.min(entryImage.getHeight(this)+3,getContentPane().getHeight());
pictureScrollPane.setBounds((getContentPane().getWidth()-w)/2,(getContentPane().getHeight()-h)/2, w, h);
pictureScrollPane.setViewportView(entry);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
/**
* action performed for undo event
* @param evt
*/
@SuppressWarnings("unchecked")
private void jMenuItem4ActionPerformed(ActionEvent evt)
{
Boolean flag = false;
if ((!entry.isDisabled) && (entry.SavedImages.size()>1)) {
if (entry.getPressed()) {
entry.entryReset();
flag = true;
}
entry.RedoImages.push(entry.SavedImages.pop());
Image tmg = createImage(((Image)entry.SavedImages.peek()).getWidth(this),((Image)entry.SavedImages.peek()).getHeight(this));
Graphics tg = tmg.getGraphics();
tg.drawImage((Image)entry.SavedImages.peek(),0,0,null);
entry.showImage(tmg);
entry.setPreferredSize(new Dimension(entryImage.getWidth(this),entryImage.getHeight(this)));
int w = Math.min(entryImage.getWidth(this)+3,getContentPane().getWidth());
int h = Math.min(entryImage.getHeight(this)+3,getContentPane().getHeight());
pictureScrollPane.setBounds((getContentPane().getWidth()-w)/2,(getContentPane().getHeight()-h)/2, w, h);
pictureScrollPane.setViewportView(entry);
if (flag) {
jMenuItem5ActionPerformed(evt);
}
}
}
/**
* action performed for redo event
* @param evt
*/
@SuppressWarnings("unchecked")
private void jMenuItem5ActionPerformed(ActionEvent evt)
{
if ((!entry.isDisabled) && (entry.RedoImages.size()>0)) {
Image tmg = createImage(((Image)entry.RedoImages.peek()).getWidth(this),((Image)entry.RedoImages.peek()).getHeight(this));
Graphics tg = tmg.getGraphics();
tg.drawImage((Image)entry.RedoImages.peek(),0,0,null);
entry.showImage(tmg);
entry.SavedImages.push(entry.RedoImages.pop());
entry.setPreferredSize(new Dimension(entryImage.getWidth(this),entryImage.getHeight(this)));
int w = Math.min(entryImage.getWidth(this)+3,getContentPane().getWidth());
int h = Math.min(entryImage.getHeight(this)+3,getContentPane().getHeight());
pictureScrollPane.setBounds((getContentPane().getWidth()-w)/2,(getContentPane().getHeight()-h)/2, w, h);
pictureScrollPane.setViewportView(entry);
}
}
/**
* action performed for saving image
* @param evt
*/
private void jMenuItem2ActionPerformed(ActionEvent evt)
{
if (outputFile == null) {
System.err.println("Error!! No file to save");
return;
}
try {
BufferedImage bi = (BufferedImage)entry.getImage();
ImageIO.write(bi, fileExtension, outputFile);
} catch (IOException e) {
System.err.println("Error!! File not saved");
}
}
/**
* action performed when user wants to save image with different name
* @param evt
*/
@SuppressWarnings("unchecked")
private void jMenuItem7ActionPerformed(ActionEvent evt)
{
JFileChooser _fileChooser = new JFileChooser();
int retval = _fileChooser.showSaveDialog(Main.this);
final String[] okFileExtensions = new String[] {"jpg", "png", "gif", "bmp", "jpeg"};
File file;
if (retval == JFileChooser.APPROVE_OPTION) {
file = _fileChooser.getSelectedFile();
Boolean flag = false;
for (String extension : okFileExtensions) {
if (file.getName().toLowerCase().endsWith(extension)) {
if (outputFile == null) {
System.err.println("Error!! No file to save");
return;
}
try {
outputFile = file;
fileExtension = extension;
BufferedImage bi = (BufferedImage)entry.getImage();
ImageIO.write(bi, fileExtension, outputFile);
System.out.println("Saved");
} catch (IOException e) {
System.err.println("Error!! File not saved");
}
flag = true;
}
}
if (!flag) {
JOptionPane.showMessageDialog(this, "Please choose a jpg, jpeg, png, bmp or gif file only.","Error",JOptionPane.ERROR_MESSAGE);
return;
}
}
}
/**
* action performed for inpaint
* @param evt
*/
private void jMenuItem8ActionPerformed(ActionEvent evt) {
if(Display.diplaay()==true){
Inpainter.halt = false;
Inpainter.completed = false;
if ( inpaintThread==null ) {
entry.setDisabled();
inpaintThread = new Thread(this);
inpaintThread.start();
}
}else{
JOptionPane.showMessageDialog(this, "Can't Run");
}
}
/**
* action performed for exit
* @param evt
*/
private void jMenuItem3ActionPerformed(ActionEvent evt)
{
System.exit(0);
}
class SymAction implements java.awt.event.ActionListener {
public void actionPerformed(java.awt.event.ActionEvent event)
{
Object object = event.getSource();
}
}
/**
* calls the method to start inpainting
*/
public void run()
{
Inpainter.init((BufferedImage)entry.getImage(), (BufferedImage)entry.getImage(),fastInpaint);
}
/**
* Method to communicate with the Inpainting module
* @param toShow updated image
*/
public void updateStats(BufferedImage toShow)
{
UpdateStats stats = new UpdateStats();
stats.toShow = toShow;
try {
SwingUtilities.invokeAndWait(stats);
} catch ( Exception e ) {
JOptionPane.showMessageDialog(this,"Error: " + e,"Training",
JOptionPane.ERROR_MESSAGE);
}
if (Inpainter.completed) { // Inpainting completes
JOptionPane.showMessageDialog(this,
" Inpainting is completed.","Inpainting",
JOptionPane.PLAIN_MESSAGE);
}
if (Inpainter.completed || Inpainter.halt) {
System.out.println ("Inpainting completed or halted");
inpaintThread = null;
Image tmg = createImage(((Image)toShow).getWidth(this),((Image)toShow).getHeight(this));
Graphics tg = tmg.getGraphics();
tg.drawImage((Image)toShow,0,0,null);
entry.SavedImages.push(tmg);
entry.setEnabled();
entry.RedoImages.clear();
fastInpaint = false;
}
}
public class UpdateStats implements Runnable {
BufferedImage toShow;
public void run()
{
entry.showImage(toShow);
}
}
}
PACKAGE
INPAINT
IMAGEINPAINT.JAVA
package inpaint;
import imageselection.GradientCalculator;
import java.util.*; // Packages for basic Java utilities, e.g. Vector etc.
import java.awt.*; // Packages for Java Images
import java.awt.image.*; // Packages for Image processing in Java
import java.awt.image.PixelGrabber; // Package for grabbing Pixels from the Image
import imageselection.Main; // Application's Main class
/**
* Class to Inpaint the given Image.
* Call Function init with original image, fillImage and quickPaint as arguments
* @author Sapan & Pulkit
*/
public class ImageInpaint {
BufferedImage origImg; // BufferedImage Object to represent updated image at every step
Image fillImg; // Image Object to represent Image with target region marked
BufferedImage img; // BufferedImage Object to represent original Image
WritableRaster raster; // Raster to write to the image
int iw, ih; // iw: Width of Image, ih: Height of Image
int pixels[]; // Temporary array that will initially store the grabbed pixels
int pixelmap[][]; // Matrix to store the pixels of original image
int fillPixelmap[][]; // Matrix to store the pixels of image marked with target region
int sourceRegion[][]; // Matrix to store Boolean values for Source Region (is updated after each iteration)
int initialSourceRegion[][]; // Matrix to store Boolean values for Initial Source Region
double fillRegion[][]; // Matrix to store Boolean values for Target Region
double gradientX[][]; // Matrix to represent the perpendicular Gradient at each point in X direction
double gradientY[][]; // Matrix to represent the perpendicular Gradient at each point in Y direction
double confidence[][]; // Matrix that stores the Confidence values for each pixel
double data[][]; // Matrix to store the data terms for each pixel
GradientCalculator gc; // Object of GradientCalculator class used to calculate gradient
double omega = 0.7; // Represents the omega used in confidence term
double Alpha = 0.2; // Represents the multiplier for confidence term in calculating priority
double Beta = 0.8; // Represents the multiplier for data term in calculating priority
int maxX; // The maximum X coordinate of the target region
int maxY; // The maximum Y coordinate of the target region
int minX; // The minimum X coordinate of the target region
int minY; // The minimum Y coordinate of the target region
int continuousCol = 0; // The maximum number of continuous green pixels in one column
int continuousRow = 0; // The maximum number of continuous green pixels in one row
protected Main owner; // Object to the Main Class. Used in passing updates after every iteration
public Boolean halt = false; // Used to stop inpainting.
public Boolean completed = false; // Used to report when the inpainting is complete.
final int diamX = 50; // Diameter (in X direction) of the Region to be searched for
final int diamY = 30; // Diameter (in Y direction) of the Region to be searched for
private int pixelPosX; // The X-coordinate of current pixel being processed
private int pixelPosY; // The Y-coordinate of current pixel being processed
int w = 3; // Patch size is 2*w + 1
double con[][] = new double[][] {{1, 1, 1}, {1, -8, 1}, {1, 1, 1}}; //Laplacian filter used in founding boundary of target region
/**
* Constructor for the ImageInpaint Class
* @param owner Object to the Main class representing the owner of ImageInpaint object.
*/
public ImageInpaint(Main owner) {
this.owner = owner;
}
/**
* Function to inpaint the given image.
* @param a_origImg Original Image (without the target region marked)
* @param a_fillImg Image with the target region marked in green color
* @param quickInpaint Flag to specify whether quick painting is enabled or not
*/
@SuppressWarnings("unchecked")
public void init(BufferedImage a_origImg, BufferedImage a_fillImg, Boolean quickInpaint)
{
halt = false;
int i, j;
try {
origImg = a_origImg;
img = a_origImg;
fillImg = a_fillImg;
raster = origImg.getRaster();
iw = img.getWidth(null);
ih = img.getHeight(null);
/**
* Grab the pixels of Original Image.
*/
pixels = new int[iw*ih];
PixelGrabber pg = new PixelGrabber(img, 0, 0, iw, ih, pixels, 0, iw);
pg.grabPixels();
pixelmap = new int[ih][iw];
for (i = 0; i < ih; i ++) {
for (j = 0; j < iw; j ++) {
pixelmap[i][j] = pixels [i*iw+j];
}
}
/**
* Grab the pixels of Fill Image.
*/
PixelGrabber fillPg = new PixelGrabber(fillImg, 0, 0, iw, ih, pixels, 0, iw);
fillPg.grabPixels();
fillPixelmap = new int[ih][iw];
for (i = 0; i < ih; i ++) {
for (j = 0; j < iw; j ++) {
fillPixelmap[i][j] = pixels [i*iw+j];
}
}
} catch (InterruptedException e1) {
javax.swing.JOptionPane.showMessageDialog(owner, "Error " + e1,"Error!!",
javax.swing.JOptionPane.ERROR_MESSAGE);
System.out.println("Error " + e1);
}
/**
* Create instance of GradientCalculator to calculate gradients.
*/
gc = new GradientCalculator();
gc.calculateGradientFromImage(pixelmap, ih, iw); // Calculate Perpendicular Gradient for original image.
gradientX = gc.gradientX;
gradientY = gc.gradientY;
initialize_confidence_term(); // Initialize the confidence term
initialize_data_term(); // Initialize the data term
fillRegion = new double[ih][iw]; // Allocate Space for fillRegion
sourceRegion = new int[ih][iw]; // Allocate Space for SourceRegion
initialSourceRegion = new int[ih][iw]; // Allocate Space for initialSourceRegion
/**
* Initialize minX, minY, maxX and maxY to find these coordinates
*/
minX = iw;
minY = ih;
maxX = maxY = 0;
int pixel, r, g, b, countrow, countcol;
continuousRow = continuousCol = 0;
for (i = 0; i < ih; i ++) {
countrow = 0;
for (j = 0; j < iw; j ++) {
pixel = fillPixelmap[i][j];
r = 0xff & (pixel >> 16); // Obtain the red Component
g = 0xff & (pixel >> 8); // Obtain the green Component
b = 0xff & (pixel); // Obtain the blue Component
/**
* If the color is green, mark it as fillRegion
* Otherwise mark it as SourceRegion.
*/
if (r == 0 && g == 255 && b == 0) {
countrow ++; // Increase the number of continuous green pixels
fillRegion[i][j] = 1;
sourceRegion[i][j] = 0;
initialSourceRegion[i][j] = 0;
if (j < minX) {
minX = j;
}
if (i < minY) {
minY = i;
}
if (j > maxX) {
maxX = j;
}
if (i > maxY) {
maxY = i;
}
} else {
if (countrow > continuousRow) {
continuousRow = countrow;
}
countrow = 0;
fillRegion[i][j] = 0;
sourceRegion[i][j] = 1;
initialSourceRegion[i][j] = 1;
}
}
}
for (i = 0; i < iw; ++i) {
countcol = 0;
for (j = 0; j < ih; ++j) {
pixel = fillPixelmap[j][i];
r = 0xff & (pixel >> 16); // Obtain the red Component
g = 0xff & (pixel >> 8); // Obtain the green Component
b = 0xff & (pixel); // Obtain the blue Component
/**
* If pixel is green, increase the countcol by 1.
*/
if (r == 0 && g == 255 && b == 0) {
countcol ++; // Increase the number of continuous green pixels
} else {
if (countcol > continuousCol) {
continuousCol = countcol;
}
countcol = 0;
}
}
}
//System.out.println("Col = " + continuousCol);
//System.out.println("Col = " + continuousRow);
Boolean flag = true; // Flag to represent the completion of the inpainting process
double[][] temp = new double[ih][iw];
double[][] sourceGradX = new double[ih][iw];
double[][] sourceGradY = new double[ih][iw];
Vector dR = new Vector(); // Vector to store pixels of the boundary
Vector Nx = new Vector(); // Vector to store corresponding gradient in X direction
Vector Ny = new Vector(); // Vector to store corresponding gradient in Y direction
double count; // Temporary variable used in calculating confidence terms for patches
double Rcp; // Temporary variable used in calculating confidence terms for patches
double tempPriority; // Temporary variable used in calculating maximum priority
while (flag) {
/**
* Filter the fillRegion with Laplacian Filter. Done to find the pixels on the boundary.
*/
temp = conv2 (fillRegion, con);
/**
* Find the gradient of Source Region.
*/
gc.calculateGradient(sourceRegion, ih, iw);
sourceGradX = gc.gradientX;
sourceGradY = gc.gradientY;
dR.clear();
Nx.clear();
Ny.clear();
/**
* Add the coordinates of boundary pixels to dR and their gradients to Nx and Ny.
*/
for (i = 0; i < temp[0].length; i ++) {
for (j = 0; j < temp.length; j ++) {
if (temp[j][i] > 0) {
dR.add(i*temp.length + j);
Nx.add(sourceGradX[j][i]);
Ny.add(sourceGradY[j][i]);
}
}
}
double[][] N = normr(Nx, Ny); // Normalize Nx and Ny and store in N
Vector q = new Vector();
count = 0.0;
/**
* Now calculate Confidence Terms for all the pixels in the boundary of target region.
*/
for (i = 0; i < dR.size(); i ++) {
int[][] Hp = getpatch(pixelmap, (Integer)dR.get(i));
System.out.println();
for (j = 0; j < Hp.length; j ++) {
for (int k = 0; k < Hp[0].length; k ++) {
int col = (int)Hp[j][k]/ih;
int row = (int)Hp[j][k]%ih;
System.out.println(col+" "+row);
if (fillRegion[row][col] == 0) {
count += confidence[row][col];
q.add(Hp[j][k]);
}
}
}
int col = (Integer)dR.get(i)/ih;
int row = (Integer)dR.get(i)%ih;
confidence[row][col] = count/(double)(Hp.length*Hp[0].length);
count = 0;
}
double maxPriority = 0.0;
int maxPriorityIndex = -1;
/**
* After calculating confidence terms, now calculate data term and then find the patch with maximum priority.
* This is done using the additive priority term.
*/
for (i = 0; i < dR.size(); i ++) {
int col = (Integer)dR.get(i)/ih;
int row = (Integer)dR.get(i)%ih;
/**
* Calculate Data term. +0.001 to prevent it from getting value Zero.
*/
data[row][col] = Math.abs(gradientX[row][col]*N[i][0] + gradientY[row][col]*N[i][1]) + 0.001;
/**
* Elevated Confidence term. This prevents it from reaching Zero to soon.
*/
Rcp = (1-omega)*confidence[row][col]+omega;
tempPriority = Alpha*Rcp + Beta*data[row][col]; // Calculate Priority using additive function
/**
* find the patch with maximum priority
*/
if (tempPriority >= maxPriority) {
maxPriority = tempPriority;
maxPriorityIndex = i;
}
}
if (maxPriorityIndex == -1) break; // If no patch is found, then inpainting is complete.
/**
* Obtain the patch with maximum priority.
* @Hp: Coordinates of patch with maximum priority
* @toFill: Represents which pixels (from the patch) are to be filled
* @toFillTrans: Transpose of ToFill matrix
*/
int[][] Hp = getpatch (pixelmap, (Integer)dR.get(maxPriorityIndex));
double[][] toFill = new double[Hp.length][Hp[0].length];
double[][] toFillTrans = new double[Hp[0].length][Hp.length];
/**
* Calculate ToFill and ToFillTrans
*/
for (i = 0; i < Hp.length; i ++) {
for (j = 0; j < Hp[0].length; j ++) {
int col = (int)Hp[i][j]/ih;
int row = (int)Hp[i][j]%ih;
toFill[i][j] = fillRegion[row][col];
toFillTrans[j][i] = fillRegion[row][col];
}
}
pixelPosX = (Integer)dR.get(maxPriorityIndex)/ih;
pixelPosY = (Integer)dR.get(maxPriorityIndex)%ih;
/**
* Find the Best Exemplar. if quickInpaint is set, then only a small region of complete image is scanned.
* We now get the starting and ending X and Y coordinates of the best Patch.
*/
int[] best = bestExemplar(Hp, toFillTrans, initialSourceRegion, quickInpaint);
int nRows = best[3] - best[2] + 1;
int nCols = best[1] - best[0] + 1;
/**
* Find the patch represented by best.
*/
int[][] X = new int[nRows][nCols];
int[][] Y = new int[nRows][nCols];
int[][] Hq = new int[nRows][nCols];
for (i = 0; i < nRows; i ++) {
for (j = 0; j < nCols; j ++) {
X[i][j] = best[0] + j;
Y[i][j] = best[2] + i;
Hq[i][j] = X[i][j] + Y[i][j]*ih;
}
}
int p = (Integer)dR.get(maxPriorityIndex);
/**
* Update the image, data values and confidence values.
*/
for (i = 0; i < toFill.length; i ++) {
for (j = 0; j < toFill[0].length; j ++) {
if (toFill[i][j] != 0) {
toFill[i][j] = 1;
int col = (int)Hp[i][j]/ih;
int row = (int)Hp[i][j]%ih;
int col1 = Hq[i][j]/ih;
int row1 = Hq[i][j]%ih;
fillRegion[row][col] = 0; // Since the region is reconstructed, remove from fillRegion
sourceRegion[row][col] = 1; // Since the region is reconstructed, add to SourceRegion
/** Propagate Confidence and Isophote Values */
confidence[row][col] = confidence[p%ih][p/ih];
gradientX[row][col] = gradientX[row1][col1];
gradientY[row][col] = gradientY[row1][col1];
pixelmap[row][col] = pixelmap[row1][col1];
/**
* Update the image pixels
*/
int[] color = new int[3];
color[0] = 0xff & (pixelmap[row1][col1] >> 16);
color[1] = 0xff & (pixelmap[row1][col1] >> 8);
color[2] = 0xff & (pixelmap[row1][col1]);
raster.setPixel(col, row, color);
}
}
}
if (halt) break;
owner.updateStats(origImg); // Inform the owner about the updated image.
Thread.yield();
/**
* Find whether any other pixels are remaining to be inpainted.
*/
flag = false;
for (i = 0; i < fillRegion.length; ++i) {
for (j = 0; j < fillRegion[0].length; ++j) {
if (fillRegion[i][j] == 1) {
flag = true;
break;
}
}
if (flag) break; // If none of the pixels are in target region, break
}
if (halt) break; // Stop Inpainting if owner halts the process.
}
/**
* No need of gradient calculator now.
* Mark it as null to drop a hint to garbageCollector that it can now be removed.
*/
gc = null;
if (!halt) {
completed = true;
} else {
completed = false;
}
owner.updateStats(origImg); // Inform the owner about the updates.
Thread.yield();
}
/**
* Initializes the confidence term to zero for pixels in target region and 1 for pixels in source region.
*/
void initialize_confidence_term()
{
confidence = new double[ih][iw];
for(int i = 0; i < ih; i ++) {
for (int j = 0; j < iw; j ++) {
int p = pixelmap[i][j];
int r = 0xff & (p >> 16);
int g = 0xff & (p >> 8);
int b = 0xff & (p);
if (r == 0 && g == 255 && b == 0) {
confidence[i][j] = 0;
} else {
confidence[i][j] = 1;
}
}
}
}
/**
* Initialize the data term.
*/
void initialize_data_term()
{
data = new double[ih][iw];
for (int i = 0; i < ih; i ++) {
for (int j = 0; j < iw; j ++) {
data[i][j] = -0.1;
}
}
}
/**
* Function to convolve the given matrix with another matrix
* @param a Matrix to be convolved
* @param b Matrix to be convolved with
* @return The result after convolution.
*/
double[][] conv2 (double a[][], double b[][])
{
int ra = a.length;
int ca = a[0].length;
int rb = b.length;
int cb = b[0].length;
// do full convolution
double c[][] = new double[ra+rb-1][ca+cb-1];
for (int i = 0; i < rb; i ++) {
for (int j = 0; j < cb; j ++) {
int r1 = i;
int r2 = r1 + ra - 1;
int c1 = j;
int c2 = c1 + ca - 1;
for (int k = r1; k < r2; k ++) {
for (int l = c1; l < c2; l ++) {
c[k][l] = c[k][l] + b[i][j]*a[k-r1+1][l-c1+1];
}
}
}
}
double out[][] = new double[ra][ca];
//extract region of size(a) from c
int r1 = rb/2;
int r2 = r1 + ra - 1;
int c1 = cb/2;
int c2 = c1 + ca - 1;
for (int i = r1; i < r2; i ++) {
for (int j = c1; j < c2; j ++) {
out[i-r1+1][j-c1+1] = c[i][j];
}
}
return out;
}
/**
* Function to normalize the given vectors and return them concatenated in one single matrix
* @param X Vector 1
* @param Y Vector 2
* @return The result after normalizing and then concatenating the two vectors.
*/
@SuppressWarnings("unchecked")
double[][] normr (Vector X, Vector Y )
{
double normalized[][] = new double[X.size()][2];
for (int i = 0; i < X.size(); i ++) {
double temp1 = (Double)X.get(i);
double temp2 = (Double)Y.get(i);
temp1 *= temp1;
temp2 *= temp2;
double temp3;
if(temp1 + temp2 == 0) {
temp3 = 0;
} else {
temp3 = (double)1/(temp1 + temp2);
temp3 = Math.sqrt(temp3);
}
normalized[i][0] = temp3*(Double)X.get(i);
normalized[i][1] = temp3*(Double)Y.get(i);
}
return normalized;
}
/**
* Function that returns the patch around the given pixel.
* @param pixelmap Matrix representing the pixelmap of the image.
* @param p Position of the pixel around which patch is to be calculated
* @return a matrix that contains the coordinates of the pixels that form the patch.
*/
@SuppressWarnings("unchecked")
int[][] getpatch (int[][] pixelmap, int p)
{
int y;
int x;
p = p-1;
y = (p/ih);//+ 1;
p = p % ih;
x = p+1;
int temp1 = Math.max(x-w, 0); // Starting X coordinate
int temp2 = Math.min(x+w,ih-1); // Ending X coordinate
int temp3 = Math.max(y-w,0); // Starting Y Coordinate
int temp4 = Math.min(y+w,iw-1); // Ending Y Coordinate
//int[][] X = new int[temp4-temp3+1][temp2-temp1+1];
//int[][] Y = new int[temp4-temp3+1][temp2-temp1+1];
int [][] N = new int[temp4-temp3+1][temp2-temp1+1];
for (int i = 0; i < temp4-temp3+1; i ++) {
for (int j = 0; j < temp2-temp1+1; j ++) {
//X[i][j] = temp1 + j;
//Y[i][j] = temp3 + i;
System.out.println(i+"Patching pixel value :- "+N[i][j]);
N[i][j] = temp1+j + (temp3+i)*ih;
}
}
return N;
}
/**
* Function that finds the best exemplar from the image that matches the patch given to the fucntion.
* By default, it finds the complete image to look for the best exemplar.
* But if quickInpaint is set, it only looks for the patch inside a region defined by minX, maxX, minY, maxY, diamX and diamY
* @param Hp Patch for which the best exemplar is to be found
* @param toFill Pixels that are to be filled from the patch.
* @param sourceRegion the source region from where to look for the best exemplar
* @param quickInpaint Flag that represents whether or not to perform quick Inpainting.
* @return Returns an integer array with four elements representing starting x coordinate, ending x coordinate, starting y coordinate and ending y coordinate respectively.
*/
int[] bestExemplar (int [][] Hp, double[][] toFill, int[][] sourceRegion, Boolean quickInpaint)
{
int [][] Ip = new int[toFill.length][toFill[0].length];
for (int i = 0; i < toFill[0].length; i ++) {
for (int j = 0; j < toFill.length; j ++) {
int col = (int)Hp[i][j]/ih;
int row = (int)Hp[i][j]%ih;
Ip[j][i] = pixelmap[row][col]; // transpose
}
}
int[][] rIp = new int[Ip.length][Ip[0].length];
int[][] gIp = new int[Ip.length][Ip[0].length];
int[][] bIp = new int[Ip.length][Ip[0].length];
for (int i = 0; i < Ip.length; ++i) {
for (int j = 0; j < Ip[0].length; ++j) {
/**
* Extract the RGB components of the image.
*/
rIp[i][j] = 0xff & (Ip[i][j] >> 16);
gIp[i][j] = 0xff & (Ip[i][j] >> 8);
bIp[i][j] = 0xff & (Ip[i][j]);
}
}
int mm, nn;
int startX;
int startY;
int endX;
int endY;
int m = Ip.length;
int n = Ip[0].length;
if (quickInpaint) {
startX = Math.max(0, pixelPosX - n/2 - continuousRow - diamX/2); // Set the start X coordinate above the pixel's X-coordinate by some amount
startY = Math.max(0, pixelPosY - m/2 - continuousCol -diamY/2); // Set the start Y coordinate above the pixel's Y-coordinate by some amount
endX = Math.min(pixelmap[0].length-1, pixelPosX + n/2 + continuousRow + diamX/2);
endY = Math.min(pixelmap.length-1, pixelPosY + m/2 + continuousCol + diamY/2);
mm = endY - startY + 1;
nn = endX - startX + 1;
} else {
mm = pixelmap.length;
nn = pixelmap[0].length;
startX = 0;
startY = 0;
endX = endY = 0;
}
int i,j,ii,jj,ii2,jj2,M,N,I,J;
double patchErr=0.0,err=0.0,bestErr = 99999999999999999999.0, bestPatchErr1 = 99999999999999999999.0;
int[] best = {0, 0, 0, 0};
Boolean skipPatchFlag = false;
/** for each patch */
N= startX + nn-n+1; M= startY + mm-m+1;
for (j = startX; j < N; j++) {
J = j+n-1;
for (i = startY; i < M; i++) {
I = i+m-1;
skipPatchFlag = false;
double meanR = 0.0;
double meanG = 0.0;
double meanB = 0.0;
/**
* Calculate patch error
*/
for (jj = j, jj2 = 0; jj <= J; jj++,jj2++) {
for (ii = i,ii2 = 0; ii <= I; ii++,ii2++) {
/**
* If any pixels does not belong to the source region, then skip the patch.
*/
if (sourceRegion[ii][jj]!=1) {
skipPatchFlag = true;
break;
}
if (toFill[ii2][jj2]==0) {
int rImage = 0xff & (pixelmap[ii][jj] >> 16);
int gImage = 0xff & (pixelmap[ii][jj] >> 8);
int bImage = 0xff & (pixelmap[ii][jj]);
/**
* Calculate the mean square error for the patch.
*/
err = rImage - rIp[ii2][jj2]; patchErr += err*err;
err = gImage - gIp[ii2][jj2]; patchErr += err*err;
err = bImage - bIp[ii2][jj2]; patchErr += err*err;
/**
* Calculate the mean of the color values. Used when we get two patches with same best error.
*/
meanR += rImage;
meanG += gImage;
meanB += bImage;
}
}
if (skipPatchFlag) {
break;
}
}
/**
* Update
*/
if (!skipPatchFlag && patchErr < bestErr ) {
bestErr = patchErr;
best[0] = i; best[1] = I;
best[2] = j; best[3] = J;
/**
* Calculate the variance of the patch.
*/
double patchErr1 = 0.0;
for (jj = j, jj2 = 0; jj <= J; jj++,jj2++) {
for (ii = i,ii2 = 0; ii <= I; ii++,ii2++) {
if (toFill[ii2][jj2]==1) {
int rImage = 0xff & (pixelmap[ii][jj] >> 16);
int gImage = 0xff & (pixelmap[ii][jj] >> 8);
int bImage = 0xff & (pixelmap[ii][jj]);
err = rImage - meanR; patchErr1 += err*err;
err = gImage - meanG; patchErr1 += err*err;
err = bImage - meanB; patchErr1 += err*err;
}
}
}
bestPatchErr1 = patchErr1; // Update the variance of the best patch found so far.
} else if (!skipPatchFlag && patchErr == bestErr) {
/**
* If the current patch has same error as the previous best patch
* we find the variance of this patch.
* The patch with minimum variance is now selected as the best patch.
*/
double patchErr1 = 0.0;
for (jj = j, jj2 = 0; jj <= J; jj++,jj2++) {
for (ii = i,ii2 = 0; ii <= I; ii++,ii2++) {
if (toFill[ii2][jj2]==1) {
int rImage = 0xff & (pixelmap[ii][jj] >> 16);
int gImage = 0xff & (pixelmap[ii][jj] >> 8);
int bImage = 0xff & (pixelmap[ii][jj]);
err = rImage - meanR; patchErr1 += err*err;
err = gImage - meanG; patchErr1 += err*err;
err = bImage - meanB; patchErr1 += err*err;
}
}
}
/**
* Select the new patch if it has lower variance.
* Otherwise discard.
*/
if (bestPatchErr1 > patchErr1) {
best[0] = i; best[1] = I;
best[2] = j; best[3] = J;
bestPatchErr1 = patchErr1;
}
}
patchErr = 0.0;
}
}
if (best[0] == 0 && best[1] == 0 && best[2] == 0 && best[3] == 0) {
return (bestExemplar (Hp, toFill, sourceRegion, false));
}
return best;
}
}