Changes between Initial Version and Version 1 of plugin


Ignore:
Timestamp:
Nov 29, 2010, 4:57:08 PM (13 years ago)
Author:
bpt
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • plugin

    v1 v1  
     1To implement a plugin for JPsychoMorph you need to create a Java class that overrides the Facemorph.Batchable interface:
     2
     3{{{
     4public interface Batchable {
     5    public boolean process(ImageZoomPanel izp, boolean single);
     6    public boolean initialise(PsychoMorphForm psychomorph);
     7    public void finish();
     8    public String getName();
     9}
     10}}}
     11
     12The main method is ''process'' which will be called for each image in the batch.  The ''single'' parameter is true if the processing is '''not''' operating in batch mode, but on a single loaded image.  The ImageZoomPanel allows access to the currently loaded Image and Template.
     13
     14The ''initialise'' method is called once before a batch of images, or before a single image is processed.  It allows access to the rest of the system state via the PsychoMorphForm parameter.  The ''finish'' method is called after all the images in the list have been processed, it is not called when operating on a single image.
     15
     16The ''getName'' method should return the name of the Batchable for inclusion in the ''Plugins'' menu on the psychomorph Transform window.  Both Batch and single versions of the plugin will be added to the menu.
     17
     18The class must also have a no parameter (default) constructor for initialising.  This is called both when the plugin is first loaded into the system and every time the (single or batch) menu item is clicked.
     19
     20== Examples ==
     21
     22=== Simple example ===
     23
     24An example of a simple Batchable is given below. This Batchable checks that the inner lip points are correctly positioned vertically, and swaps corresponding points if needed.
     25
     26{{{
     27import Facemorph.Template;
     28import Facemorph.psychomorph.Batchable;
     29import Facemorph.psychomorph.ImageZoomPanel;
     30import Facemorph.psychomorph.PsychoMorphForm;
     31import java.awt.geom.Point2D;
     32
     33/**
     34 * Batch corrects the mouth in the "standard" template, by checking if the top -lip is below the bottom lip points and swapping if needed
     35 */
     36public class BatchCorrectMouth implements Batchable {
     37
     38    public boolean process(ImageZoomPanel izp, boolean single) {
     39       Template tem = izp.getTemplate();
     40       int[] topMouth = {94, 95, 96, 97, 98}, bottomMouth = {99, 100, 101, 102, 103};
     41
     42       for (int i=0; i<topMouth.length; i++) {
     43            Point2D.Float p = tem.getPoint(topMouth[i]);
     44            Point2D.Float q = tem.getPoint(bottomMouth[i]);
     45            if (q.y<p.y) {
     46                float x = p.x, y=p.y;
     47                p.x=q.x; p.y=q.y;
     48                q.x=x; q.y=y;
     49            }
     50       }
     51       tem.recalculateContours();
     52       izp.setTemplate(tem);
     53       return true;
     54    }
     55
     56    public void finish() { }
     57
     58    public String getName() {
     59        return "Correct Mouth";
     60    }
     61
     62    public boolean initialise(PsychoMorphForm psychomorph) {
     63      return true;
     64    }
     65}
     66}}}
     67
     68=== Chimeric transforms ===
     69
     70Here is the chimeric transform plugin source code, it uses some built in functionality and gets input from the user:
     71
     72{{{
     73
     74import Facemorph.Template;
     75import Facemorph.Transformer;
     76import Facemorph.psychomorph.Batchable;
     77import Facemorph.psychomorph.DelineatorForm;
     78import Facemorph.psychomorph.ImageZoomPanel;
     79import Facemorph.psychomorph.PsychoMorphForm;
     80import java.awt.Image;
     81import java.awt.image.BufferedImage;
     82import javax.swing.JOptionPane;
     83
     84/**
     85 * Chimeric transform implementation
     86 */
     87public class BatchChimericTransform implements Batchable {
     88    PsychoMorphForm morphApp;
     89    float l1, l2, wid;
     90
     91    public boolean process(ImageZoomPanel izp, boolean single) {
     92        BufferedImage leftImage = DelineatorForm.checkBufferedImage(morphApp.getLeftImage());
     93        Template leftTemplate = morphApp.getLeftTemplate();
     94        BufferedImage rightImage = DelineatorForm.checkBufferedImage(morphApp.getRightImage());
     95        Template rightTemplate = morphApp.getRightTemplate();
     96        BufferedImage img = DelineatorForm.checkBufferedImage(izp.getImage());
     97
     98        Template tem = izp.getTemplate();
     99        Template outTem = new Template();
     100
     101        if (single) {
     102           morphApp.getDelineator().getImageUndoStack().push(img);
     103           morphApp.getDelineator().getTemplateUndoStack().push(tem);
     104           morphApp.getDelineator().getTransformUndoMenuItem().setEnabled(true);
     105        }
     106   
     107        Image outImg = Transformer.transformChimeric(morphApp.getWarpType(), tem, leftTemplate, rightTemplate, outTem,
     108            img, leftImage, rightImage, l1, l2, wid, true, false);
     109        izp.setImage(outImg);
     110        izp.setTemplate(outTem);
     111       return true;
     112    }
     113
     114    public void finish() { }
     115
     116    public String getName() {
     117        return "Transform Chimeric";
     118    }
     119
     120    public boolean initialise(PsychoMorphForm psychomorph) {
     121        morphApp = psychomorph;
     122
     123        String leftStr = JOptionPane.showInputDialog(morphApp.getDelineator(), "Transform level for left side", "1");
     124        String rightStr = JOptionPane.showInputDialog(morphApp.getDelineator(), "Transform level for right side", "0");
     125        int w = 50;
     126        String widthStr = JOptionPane.showInputDialog(morphApp.getDelineator(), "Width of smoothing band", "" + w);
     127        l1 = Float.parseFloat(leftStr);
     128        l2 = Float.parseFloat(rightStr);
     129        wid = Float.parseFloat(widthStr);
     130        return true;
     131    }
     132
     133}
     134
     135
     136}}}
     137
     138
     139=== Advanced example ===
     140
     141In this example we actually mess about with warping images and modifying the colours, in order to symmetrise and image in shape and / or colour.
     142
     143{{{
     144
     145import Facemorph.Template;
     146import Facemorph.Warp;
     147import Facemorph.psychomorph.Batchable;
     148import Facemorph.psychomorph.DelineatorForm;
     149import Facemorph.psychomorph.ImageZoomPanel;
     150import Facemorph.psychomorph.PsychoMorphForm;
     151import java.awt.Color;
     152import java.awt.image.BufferedImage;
     153import java.io.File;
     154import java.io.FileNotFoundException;
     155import java.io.IOException;
     156import javax.swing.JFileChooser;
     157import javax.swing.JOptionPane;
     158
     159/**
     160 * Batch symmetriser
     161 */
     162public class BatchSymmetrise implements Batchable {
     163    int[] plist;
     164    PsychoMorphForm psychomorph;
     165
     166    public boolean process(ImageZoomPanel izp, boolean single) {
     167                Template symtemp = new Template();
     168                Template template = izp.getTemplate();
     169                BufferedImage img = DelineatorForm.checkBufferedImage(izp.getImage());
     170
     171                 if (single) {
     172                    psychomorph.getDelineator().getImageUndoStack().push(img);
     173                    psychomorph.getDelineator().getTemplateUndoStack().push(template);
     174                    psychomorph.getDelineator().getTransformUndoMenuItem().setEnabled(true);
     175                }
     176                symtemp.symmetrise(template, plist, img.getWidth());
     177                symtemp.copySamples(template);
     178                Warp warp = Warp.createWarp(psychomorph.getWarpType(), img.getWidth(), img.getHeight(), img.getWidth(), img.getHeight(), false);
     179                warp.interpolate(template, symtemp, true,  true, psychomorph.getOverlap());
     180                img = warp.warpImage(img);
     181                if (psychomorph.getDelineator().getColourCheckBoxMenuItem().getState()) {
     182                    symmetrise(img);
     183                }
     184                if (psychomorph.getDelineator().getShapeCheckBoxMenuItem().getState()) {
     185                    izp.setTemplate(symtemp);
     186                } else {
     187                     //warp = new MultiscaleWarp(img.getWidth(), img.getHeight());
     188                    warp = Warp.createWarp(psychomorph.getWarpType(), img.getWidth(), img.getHeight(), img.getWidth(), img.getHeight(), false);
     189                    warp.interpolate(symtemp, template, true, true, psychomorph.getOverlap());
     190                    img = warp.warpImage(img);
     191
     192                }
     193                izp.setImage(img);
     194                return true;
     195    }
     196
     197    public boolean initialise(PsychoMorphForm psychomorph) {
     198        this.psychomorph = psychomorph;
     199        JFileChooser chooser = PsychoMorphForm.setUpFileDialog(psychomorph.getFileChooser(), "Symmetry File", "sym");
     200        psychomorph.setFileChooser(chooser);
     201
     202    int ok = psychomorph.getFileChooser().showOpenDialog(psychomorph.getDelineator());
     203    File f2 = psychomorph.getFileChooser().getSelectedFile();
     204    plist = null;
     205    if (f2 == null || ok != JFileChooser.APPROVE_OPTION) return false;
     206
     207    try {
     208        plist = Template.readSymFile(f2.getPath());
     209    } catch (FileNotFoundException ex) {
     210        JOptionPane.showMessageDialog(psychomorph.getDelineator(), "Error reading sym file " + f2 + ", error " + ex, "Symmetry file read error", JOptionPane.ERROR_MESSAGE);
     211        ex.printStackTrace();
     212        return false;
     213    } catch (IOException ex) {
     214        JOptionPane.showMessageDialog(psychomorph.getDelineator(), "Error reading sym file " + f2 + ", error " + ex, "Symmetry file read error", JOptionPane.ERROR_MESSAGE);
     215        ex.printStackTrace();
     216        return false;
     217    }
     218    return true;
     219    }
     220
     221    public void finish() { }
     222
     223    public String getName() {
     224        return "Symmetrise";
     225    }
     226
     227    void symmetrise(BufferedImage bimg) {
     228    int x, y, r, g, b;
     229    int r1, g1, b1, r2, g2, b2;
     230
     231    for (x=0; x<bimg.getWidth()/2; x++)
     232                for (y=0; y<bimg.getHeight(); y++)
     233                {
     234                        int rgb1 = bimg.getRGB(x, y);
     235                        Color c1 = new Color(rgb1);
     236                        r1 = c1.getRed();
     237                        g1 = c1.getGreen();
     238                        b1 = c1.getBlue();
     239                        int rgb2 = bimg.getRGB(bimg.getWidth()-x-1, y);
     240                        Color c2 = new Color(rgb2);
     241                        r2 = c2.getRed();
     242                        g2 = c2.getGreen();
     243                        b2 = c2.getBlue();
     244                        r = (r1+r2)/2;
     245                        g = (g1+g2)/2;
     246                        b = (b1+b2)/2;
     247                        Color c = new Color(r, g, b);
     248                        bimg.setRGB(x, y, c.getRGB());
     249                        bimg.setRGB(bimg.getWidth()-x-1, y, c.getRGB());
     250            }
     251
     252      }
     253}
     254
     255}}}