//***************************************************************************
// Mollweide-projection into wrapable rectangle
// Petri Ihalainen
// 22-Nov-2013
// Version 1.0
//***************************************************************************
import java.awt.Image;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.File;
//======================
// YOUR SETTINGS BELOW
//======================
String WorkDir = "C:\\Documents and Settings\\Ihalainen\\Työpöytä\\"; // NOTE THE DOUBLE BACK-SLASHES!!
String MollweideName = "Mollweide-projection.jpg";
String RectangleName = "Rectangle-projection"; // No file-extension here! The script will add it.
String SavingFormat = "png"; // png, jpg, gif or bmp should work
Boolean InterpolatePixels = true; // true for quality, false for speed
//Use these if the original image e.g. has a frame area
int ExcludePixelsTop = 0;
int ExcludePixelsBottom = 0;
int ExcludePixelsLeft = 0;
int ExcludePixelsRight = 0;
//=======================================================================================================
// End of settings
//=======================================================================================================
//=========================
// Methods
//=========================
//---------------------
// Iterate Theta
//---------------------
float IterateTheta(float phi)
{
// The iteration was said to be slow by poles but I have not noticed.
t = phi;
float t1 = 0.0f;
while (Math.abs(t1-t) > 0.00001)
{
t = t1;
t1 = t - (float)((2.0f*t + Math.sin(2.0f*t)-Math.PI*Math.sin(phi))/(2.0f+2.0f*Math.cos(2.0f*t)));
}
return t;
}
//---------------------------------
// Interpolate between four pixels
//---------------------------------
Color getBlendedColor(BufferedImage img, int w, int h, int exL, int exT, float x, int r0, int r1, float wr0, float wr1)
{
int c00,c01,c10,c11;
int red,green,blue;
float c,wc00=0.5f,wc01=0.5f,wc10=0.5f,wc11=0.5f;//,wc;
Color p00,p10,p01,p11;
// weights on upper row
ym0 = ((r0 + 0.5f) - h*0.5f)/h*2.0f;
xm0 = (float)(Math.sqrt(1.0 - ym0*ym0)*x);
cm0 = (w/2.0f + xm0*w/2.0f);
c00 = (int)cm0;
c10 = c00;
cRes0 = cm0 - c00;
if (cRes0 < 0.5)
{
c00--;
wc00 = 0.5f - cRes0;
wc10 = 0.5f + cRes0;
}
if (cRes0 > 0.5)
{
c10++;
wc00 = 1.5f - cRes0;
wc10 = cRes0-0.5f;
}
// weights on lower row
ym1 = ((r1 + 0.5f) - h*0.5f)/h*2.0f;
xm1 = (float)(Math.sqrt(1.0 - ym1*ym1)*x);
cm1 = (w/2.0f + xm1*w/2.0f);
c01 = (int)cm1;
c11 = c01;
cRes1 = cm1 - c01;
if (cRes1 < 0.5)
{
c01--;
wc01 = 0.5f - cRes1;
wc11 = 0.5f + cRes1;
}
if (cRes1 > 0.5)
{
c11++;
wc01 = 1.5f - cRes1;
wc11 = cRes1-0.5f;
}
if (c00<0) c00=0;
if (c01>w-1) c01=w-1;
if (c10<0) c10=0;
if (c11>w-1) c11=w-1;
p00 = new Color(img.getRGB(c00+exL,r0+exT),false);
p10 = new Color(img.getRGB(c10+exL,r0+exT),false);
p01 = new Color(img.getRGB(c01+exL,r1+exT),false);
p11 = new Color(img.getRGB(c11+exL,r1+exT),false);
red = (int)(p00.getRed()*wc00*wr0 + p10.getRed()*wc10*wr0 + p01.getRed()*wc01*wr1 + p11.getRed()*wc11*wr1 +0.5f);
green = (int)(p00.getGreen()*wc00*wr0 + p10.getGreen()*wc10*wr0 + p01.getGreen()*wc01*wr1 + p11.getGreen()*wc11*wr1+0.5f);
blue = (int)(p00.getBlue()*wc00*wr0 + p10.getBlue()*wc10*wr0 + p01.getBlue()*wc01*wr1 + p11.getBlue()*wc11*wr1 +0.5f);
// print (red + " " + green +" "+ blue);
if (red > 255) red=255; if (red < 0) red=0;
if (green > 255) green=255; if (green < 0) green=0;
if (blue > 255) blue=255; if (blue < 0) blue=0;
return (new Color(red,green,blue));
}
//--------------------------------------------------------------------
// Create rectangle image by interpolating the over the closest pixels
//--------------------------------------------------------------------
BufferedImage InterpolatedImage(BufferedImage imgMoll, int ExT, int ExB, int ExL, int ExR)
{
int w = imgMoll.getWidth()-ExL-ExR;
int h = imgMoll.getHeight()-ExT-ExB;
BufferedImage imgRect = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
g2rect = imgRect.createGraphics();
int row, col;
int r0,r1;
float r,wr0=0.5f,wr1=0.5f,wr;
float xRect, yRect, yMoll, yMPI2, xMoll, theta, phiRect, pi = (float)Math.PI;
yMPI2 = (float)(Math.PI / Math.sqrt(2.0) * Math.sin(Math.PI /2.0)); // This is neede scale y to [-1.0 ... 1.0]
for (row=0; row<h; row++)
{
print ("row " + (row + 1) + " of " + h);
yRect = (-h/2.0f + row+0.5f)/(h/2.0f); // The rectangle y
phiRect = yRect*pi/2.0f; // Convert y to vertical angle
theta = IterateTheta((float)phiRect); // a Mollweide variable iterated
yMoll = (float)(Math.PI / Math.sqrt(2.0) * Math.sin(theta))/yMPI2; // the Mollwide y
r = h/2.0f + yMoll*h/2.0f;
r0 = (int)r;
r1 = r0;
wr = r-(int)r;
wr0 = 1.0f-wr1;
if (wr<0.5f) {
r0--;
wr0 = 0.5f - wr;
wr1 = 0.5f + wr;}
if (wr>0.5f){
r1++;
wr0 = 1.5f - wr;
wr1 = wr-0.5f;}
if (r0<0) r0=0;
if (r1>h-1) r1=h-1;
for (col=0; col<w; col++)
{
xRect = (-w/2.0f + col + 0.5f)/(w/2.0f); // The rectangle
g2rect.setColor(getBlendedColor(imgMoll, w, h, ExL, ExT, xRect, r0, r1, wr0, wr1));
g2rect.drawLine(col,row,col,row);
}
}
return imgRect; // INTERPOLATED
}
//-------------------------------------------------------------------
// Create a rectangular image by picking the closest pixel
//-------------------------------------------------------------------
BufferedImage PickedImage(BufferedImage imgMoll, int ExT, int ExB, int ExL, int ExR)
{
int w = imgMoll.getWidth()-ExL-ExR;
int h = imgMoll.getHeight()-ExT-ExB;
BufferedImage imgRect = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
g2rect = imgRect.createGraphics();
int row, col;
float r,wr0=0.5f,wr1=0.5f,wr;
float xRect, yRect, yMoll, yMPI2, xMoll, theta, phiRect, pi = (float)Math.PI;
yMPI2 = (float)(Math.PI / Math.sqrt(2.0) * Math.sin(Math.PI /2.0)); // This is needed to scale y to [-1.0 ... 1.0]
for (row=0; row<h; row++)
{
print ("row " + (row + 1) + " of " + h);
yRect = (-h/2.0f + row+0.5f)/(h/2.0f); // The rectangle y
phiRect = yRect*pi/2.0f; // Convert y to vertical angle
theta = IterateTheta((float)phiRect); // a Mollweide variable iterated
yMoll = (float)(Math.PI / Math.sqrt(2.0) * Math.sin(theta))/yMPI2; // the Mollwide y
for (col=0; col<w; col++)
{
xRect = (-w/2.0f + col + 0.5f)/(w/2.0f); // The rectangle x
xMoll = (float)Math.sqrt(1.0 - yMoll*yMoll) * xRect; // The Mollweide-x provided by Pythagoras
rMoll = (int)(h/2.0f + yMoll*h/2.0f)+ExT; // y to a pixel row
cMoll = (int)(w/2.0f + xMoll*w/2.0f)+ExL; // x to a pixel column
g2rect.setColor(new Color(imgMoll.getRGB(cMoll,rMoll),false));
g2rect.drawLine(col,row,col,row);
}
}
return imgRect; // PICKED
}
//=========================================================
// Doing the job in a thread so you can follow the progress
//=========================================================
new Thread()
{public void run() {
//--------------------
// Some prework
//--------------------
String ReadPath = WorkDir + MollweideName;
String WritePath = WorkDir + RectangleName + "." + SavingFormat;
BufferedImage imgMoll = null;
//------------------------
// Reading the input image
//------------------------
print ("Loading " + ReadPath);
try
{imgMoll = ImageIO.read(new File(ReadPath));}
catch (IOException e)
{print ("Not found");
return;}
print ("Input image height "+imgMoll.getHeight()+" pixels");
print ("Input image width "+imgMoll.getWidth()+" pixels");
//-----------------------
// Get the new image
//-----------------------
t0 = System.currentTimeMillis();
BufferedImage imgRect;
if (InterpolatePixels)
imgRect = InterpolatedImage(imgMoll, ExcludePixelsTop, ExcludePixelsBottom, ExcludePixelsLeft, ExcludePixelsRight);
else
imgRect = PickedImage(imgMoll, ExcludePixelsTop, ExcludePixelsBottom, ExcludePixelsLeft, ExcludePixelsRight);
//----------------------
// Saving the new image
//----------------------
try
{
print ("Saving " + WritePath);
ImageIO.write(imgRect, SavingFormat, new File(WritePath));
}
catch (IOException e)
{
print ("Error in saving " + WritePath);
}
//--------------------
// End :)
//--------------------
t1 = System.currentTimeMillis();
print ("Processing competed in " + (t1-t0)/1000.0 + " seconds");
}
}.start();