How to separately texturize (with different texture files) a 3D model? - java

I have a 3D file made in Blender and exported to java (.OBJ file), which has his textures separated into some files. Inside this .obj file, it has some fields caled USEMTL and the name of its parts (textures files). However, when I draw it at the screen, he only shows the last USEMTL name.
My question is: How can i proceed to make him read and texturize at the correct way? Without lapping other textures?
This is the class that have the .obj loader
public MLoader(String path, Model m) throws IOException {
#SuppressWarnings("resource")
BufferedReader reader = new BufferedReader(new FileReader(new File(path)));
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("v ")) {
float
v1 = Float.valueOf(line.split(" ")[1]),
v2 = Float.valueOf(line.split(" ")[2]),
v3 = Float.valueOf(line.split(" ")[3]);
Vector3f v = new Vector3f (v1, v2, v3);
m.vertex.add(v);
} if (line.startsWith("usemtl ")){
String name = String.valueOf(line.split(" ")[1]);
m.nameTexture.add(name);
continue;
} if (line.startsWith("f ")) {
float
v1 = Float.valueOf(line.split(" ")[1].split("/")[0]),
v2 = Float.valueOf(line.split(" ")[2].split("/")[0]),
v3 = Float.valueOf(line.split(" ")[3].split("/")[0]),
n1 = Float.valueOf(line.split(" ")[1].split("/")[1]),
n2 = Float.valueOf(line.split(" ")[2].split("/")[1]),
n3 = Float.valueOf(line.split(" ")[3].split("/")[1]);
Vector3f
v = new Vector3f (v1, v2, v3),
n = new Vector3f (n1, n2, n3);
m.face.add(new Faces(v, n));
}if (line.startsWith("vt ")) {
float
vt1 = Float.valueOf(line.split(" ")[1]),
vt2 = Float.valueOf(line.split(" ")[2]);
Vector2f vt = new Vector2f (vt1, vt2);
m.vertexTexture.add(vt);
}
}
}
As you can see, I created a IF statement, just to get this usemtl stuff (that is inside .obj file) - the texture names (which are into separate files) just to see if I could bind them individually. But I'm having trouble to do that (perhaps, logic isn't in my side). How to proceed?
Other classes:
Texture Class
public class Textures {
public Texture[] tx;
public void setNumTex(int i) {
tx = new Texture[i];
}
public void setTexture(String format, String name, int i) {
try {
tx[i] = TextureLoader.getTexture(format, new FileInputStream(new File("res/Textures/" + name + format)));
} catch (IOException e) {
e.printStackTrace();
}
}
public void texturing(Vector2f ft1, Vector2f ft2, int indexx) {
for (int i=0; i<indexx; i++) {
tx[i].bind();
}
glTexCoord2f(ft1.x, ft1.y);
glTexCoord2f(ft2.x, ft2.y);
}
}
Render Class
public class Renderer {
Model m;
public void loadContent(String objPath) {
//Everithing that is loading is been putting here
m = Model.getModel("res/Models/" + objPath);
m.loadTex();
}
public void render() {
glEnable(GL_SMOOTH);
m.renderModel();
}
}
Model Class
public class Model {
Textures tx;
List<Vector3f> vertex, norms;
List<Vector2f> vertexTexture;
List<Faces> face;
List<String> nameTexture;
String name[];
private int numTex = 0;
Vector2f
t1 = new Vector2f(), t2 = new Vector2f();
Vector3f
v1 = new Vector3f(), v2 = new Vector3f(), v3 = new Vector3f(),
n1 = new Vector3f(), n2 = new Vector3f(), n3 = new Vector3f(),
public Model(String path)throws
LWJGLException, FileNotFoundException, IOException {
vertex = new ArrayList<Vector3f>();
norms = new ArrayList<Vector3f>();
vertexTexture = new ArrayList<Vector2f>();
face = new ArrayList<Faces>();
nameTexture = new ArrayList<String>();
tx = new Textures();
new MLoader(path, this);
}
public static Model getModel(String path, Vector3f position, Vector3f rotation) {
try {
return new Model(path, position, rotation);
} catch (LWJGLException | IOException e) {
e.printStackTrace();
}
return null;
}
public void loadTex() {
name = new String[nameTexture.toArray().length];
tx.setNumTex(nameTexture.toArray().length);
for (int i=0; i<name.length; i++) {
name[i] = nameTexture.get(i);
numTex += 1;
tx.setTexture(".TGA", name[i], i);
}
}
public void renderModel() {
glPushMatrix();
glPolygonMode(GL_FRONT_AND_BACK, GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glBegin(GL_TRIANGLES);
{
for (Faces f : face) {
v1 = vertex.get((int) f.v.x - 1);
v2 = vertex.get((int) f.v.y - 1);
v3 = vertex.get((int) f.v.z - 1);
n1 = vertex.get((int) f.n.x - 1);
n2 = vertex.get((int) f.n.y - 1);
n3 = vertex.get((int) f.n.z - 1);
t1 = vertexTexture.get((int) f.n.x - 1); //
t2 = vertexTexture.get((int) f.n.y - 1); //
//Vertexes
glVertex3f(v1.x, v1.y-3.4f, v1.z-0.53f);
glVertex3f(v2.x, v2.y-3.4f, v2.z-0.53f);
glVertex3f(v3.x, v3.y-3.4f, v3.z-0.53f);
//Normals
glNormal3f(n1.x, n1.y-3.4f, n1.z-0.53f);
glNormal3f(n2.x, n2.y-3.4f, n2.z-0.53f);
glNormal3f(n3.x, n3.y-3.4f, n3.z-0.53f);
//Texture
tx.texturing(t1, t2, numTex);
//tx.texturing(n1, n2, n3);
}
}
glEnd();
glDisable(GL_TEXTURE_2D);
glPopMatrix();
}
}

I will not put any code as your question is pretty complex for a 2 line solution.But here how it is usually works in a simple 3D engine.Multiple texturing of a mesh implies that the mesh is broken into 2 or more sub-meshes.I am not blender specialist but I am sure it is capable of exporting the mesh with its sub-mesh tree just like Autodesk 3D studio max.Now,when you import such a mesh into your program you should be able to parse all those sub-meshes into separate entities.Every such a sub-mesh has its own vertices,texture coordinates and normals. When issuing the draw call you would iterate over all the sub-meshes one by one and draw each of them in its own draw call.So on on each draw call you should be able also to attach a unique texture to be used for that specific sub-mesh.That's all.Now it is up to you how to design such a system.
Hope it helps.

Okay, I discovered what was the problem.
Here's the solution: At the class MLoader, I had just to put a "distinguisher" at the "usemtl" part. With it, when he is at the "F SECTION", when he returns and adds to "faceArray" thing the face, he just adds more then he needs.
Example:
face.add(1, 2, 3);
faceArray.add(face); //Assuming that the face has his 1, 2, 3 thing
when he goes again to the "f" if, he adds
face.add(4, 5, 6);
faceArray.add(face); //But, this time, when he adds the face, it already had 1, 2, 3,
//so, he's with '1, 2, 3, 4, 5, 6' into him
Here's the changse i've made (just the changes):
Class MLoader:
public MLoader(String path, Model m) throws IOException {
...
while ((line = reader.readLine()) != null) {
...
} if (line.contains("g ")) {
index = 0;
} if (line.startsWith("usemtl ") && index == 0){
String name = String.valueOf(line.split(" ")[1]);
m.nameTexture.add(name);
m.faceArray.add(m.face);
m.face = new ArrayList<Faces>();
index = 1;
} if (line.contains("f ") && index == 1) {
...
}
Class Model:
int numTex = 0;
List<List <Faces>> faceArray;
...
public void loadTex() {
for (String n : nameTexture) {
tx.loadTexture("TGA", n);
numTex ++;
}
}
...
public void renderModel() {
...
glEnable(GL_TEXTURE_2D);
for (int i = 0; i < numTex; i++) {
tx.tx.get(i).bind();
glBegin(GL_TRIANGLES);
{
for (Faces f : faceArray.get(i)) {
...
}
}
glEnd();
}
glDisable(GL_TEXTURE_2D);
...
}

Related

How to pick specific parts of a Shape3D shape (processing)

I am attempting to make a voxel-ish world builder, and I need to be able to stack the different blocks. How can I pick the separate sides of the block with the shapes3d library. Whenever I pick the shape, it renders it as the entire shape, and I am unsure of how to select only the part that I would like, so that I can build upon it.
import peasy.*;
import shapes3d.*;
import shapes3d.utils.*;
Shape3D picked = null;
boolean clicked = true;
PeasyCam cam;
float[] xArr,yArr,zArr;
float x,y,z;
Box[] boxArr;
color[] colArr;
CameraState defaultState;
void setup(){
size(1200,800,P3D);
cam = new PeasyCam(this,width/2,height/2,0,500);
cam.setMinimumDistance(200);
cam.setMaximumDistance(2000);
cam.setWheelScale(.05);
cam.setDistance(1000);
cam.rotateZ(PI/4);
cam.rotateX(-PI/3);
cam.setResetOnDoubleClick(false);
defaultState = cam.getState();
x=width/2;
y=height/2;
z=0;
xArr = new float[200];
yArr = new float[200];
zArr = new float[200];
colArr = new color[200];
boxArr= new Box[200];
for(int i=0;i<boxArr.length;i++){
boxArr[i]=null;
}
xArr[0]=x;
yArr[0]=y;
zArr[0]=z;
boxArr[0]=new Box(this);
colArr[0]=color(255,255,255);
}
final float xrot=-PI/8,yrot=PI/4,zrot=0;
color col = color(255,255,255);
void mouseClicked(){
clicked=true;
}
void draw(){
pushMatrix();
if (keyPressed&&key=='r'){
cam.setState(defaultState);
cam.setDistance(1000);
}
background(213, 243, 245);
ambientLight(200,200,200);
fill(col);
lights();
directionalLight(100,100,100,50,-50,0);
int actuallength=0;
for (int i=0;i<boxArr.length;i++){
if(boxArr[i]!=null){
actuallength++;
}
}
for(int i = 0; i<actuallength; i++){
boxArr[i].fill(colArr[i]);
boxArr[i].strokeWeight(1.75);
boxArr[i].stroke(155);
boxArr[i].moveTo(xArr[i],yArr[i],zArr[i]);
boxArr[i].drawMode(Shape3D.SOLID|Shape3D.WIRE);
boxArr[i].draw();
}
if (clicked){
clicked=false;
picked = Shape3D.pickShape(this, mouseX, mouseY);
int pos=0;
for(int i=0;i<boxArr.length;i++){
if(boxArr[i]==picked){
pos=i;
}
}
if(picked!=null){
println();
boxArr[actuallength]=new Box(this);
xArr[actuallength]=xArr[pos]+(100);
yArr[actuallength]=yArr[pos];
zArr[actuallength]=zArr[pos];
colArr[actuallength]=color(255,255,255);
}
}
popMatrix();
}

PDFBox - Line / Rectangle extraction

I am trying to extract text coordinates and line (or rectangle) coordinates from a PDF.
The TextPosition class has getXDirAdj() and getYDirAdj() methods which transform coordinates according to the direction of the text piece the respective TextPosition object represents (Corrected based on comment from #mkl)
The final output is consistent, irrespective of the page rotation.
The coordinates needed on the output are X0,Y0 (TOP LEFT CORNER OF THE PAGE)
This is a slight modification from the solution by #Tilman Hausherr. The y coordinates are inverted (height - y) to keep it consistent with the coordinates from the text extraction process, also the output is written to a csv.
public class LineCatcher extends PDFGraphicsStreamEngine
{
private static final GeneralPath linePath = new GeneralPath();
private static ArrayList<Rectangle2D> rectList= new ArrayList<Rectangle2D>();
private int clipWindingRule = -1;
private static String headerRecord = "Text|Page|x|y|width|height|space|font";
public LineCatcher(PDPage page)
{
super(page);
}
public static void main(String[] args) throws IOException
{
if( args.length != 4 )
{
usage();
}
else
{
PDDocument document = null;
FileOutputStream fop = null;
File file;
Writer osw = null;
int numPages;
double page_height;
try
{
document = PDDocument.load( new File(args[0], args[1]) );
numPages = document.getNumberOfPages();
file = new File(args[2], args[3]);
fop = new FileOutputStream(file);
// if file doesnt exists, then create it
if (!file.exists()) {
file.createNewFile();
}
osw = new OutputStreamWriter(fop, "UTF8");
osw.write(headerRecord + System.lineSeparator());
System.out.println("Line Processing numPages:" + numPages);
for (int n = 0; n < numPages; n++) {
System.out.println("Line Processing page:" + n);
rectList = new ArrayList<Rectangle2D>();
PDPage page = document.getPage(n);
page_height = page.getCropBox().getUpperRightY();
LineCatcher lineCatcher = new LineCatcher(page);
lineCatcher.processPage(page);
try{
for(Rectangle2D rect:rectList) {
String pageNum = Integer.toString(n + 1);
String x = Double.toString(rect.getX());
String y = Double.toString(page_height - rect.getY()) ;
String w = Double.toString(rect.getWidth());
String h = Double.toString(rect.getHeight());
writeToFile(pageNum, x, y, w, h, osw);
}
rectList = null;
page = null;
lineCatcher = null;
}
catch(IOException io){
throw new IOException("Failed to Parse document for line processing. Incorrect document format. Page:" + n);
}
};
}
catch(IOException io){
throw new IOException("Failed to Parse document for line processing. Incorrect document format.");
}
finally
{
if ( osw != null ){
osw.close();
}
if( document != null )
{
document.close();
}
}
}
}
private static void writeToFile(String pageNum, String x, String y, String w, String h, Writer osw) throws IOException {
String c = "^" + "|" +
pageNum + "|" +
x + "|" +
y + "|" +
w + "|" +
h + "|" +
"999" + "|" +
"marker-only";
osw.write(c + System.lineSeparator());
}
#Override
public void appendRectangle(Point2D p0, Point2D p1, Point2D p2, Point2D p3) throws IOException
{
// to ensure that the path is created in the right direction, we have to create
// it by combining single lines instead of creating a simple rectangle
linePath.moveTo((float) p0.getX(), (float) p0.getY());
linePath.lineTo((float) p1.getX(), (float) p1.getY());
linePath.lineTo((float) p2.getX(), (float) p2.getY());
linePath.lineTo((float) p3.getX(), (float) p3.getY());
// close the subpath instead of adding the last line so that a possible set line
// cap style isn't taken into account at the "beginning" of the rectangle
linePath.closePath();
}
#Override
public void drawImage(PDImage pdi) throws IOException
{
}
#Override
public void clip(int windingRule) throws IOException
{
// the clipping path will not be updated until the succeeding painting operator is called
clipWindingRule = windingRule;
}
#Override
public void moveTo(float x, float y) throws IOException
{
linePath.moveTo(x, y);
}
#Override
public void lineTo(float x, float y) throws IOException
{
linePath.lineTo(x, y);
}
#Override
public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) throws IOException
{
linePath.curveTo(x1, y1, x2, y2, x3, y3);
}
#Override
public Point2D getCurrentPoint() throws IOException
{
return linePath.getCurrentPoint();
}
#Override
public void closePath() throws IOException
{
linePath.closePath();
}
#Override
public void endPath() throws IOException
{
if (clipWindingRule != -1)
{
linePath.setWindingRule(clipWindingRule);
getGraphicsState().intersectClippingPath(linePath);
clipWindingRule = -1;
}
linePath.reset();
}
#Override
public void strokePath() throws IOException
{
rectList.add(linePath.getBounds2D());
linePath.reset();
}
#Override
public void fillPath(int windingRule) throws IOException
{
linePath.reset();
}
#Override
public void fillAndStrokePath(int windingRule) throws IOException
{
linePath.reset();
}
#Override
public void shadingFill(COSName cosn) throws IOException
{
}
/**
* This will print the usage for this document.
*/
private static void usage()
{
System.err.println( "Usage: java " + LineCatcher.class.getName() + " <input-pdf>" + " <output-file>");
}
}
Was using the PDFGraphicsStreamEngine class to extract Line and Rectangle coordinates. The coordinates of lines and rectangles do not align with the coordinates of the text
Green: Text
Red: Line coordinates obtained as is
Black: Expected coordinates (Obtained after applying transformation on the output)
Tried the setRotation() method to correct for the rotation before running the line extract. However the results are not consistent.
What are the possible options to get the rotation and get a consistent output of the Line / Rectangle coordinates using PDFBox?
As far as I understand the requirements here, the OP works in a coordinate system with the origin in the upper left corner of the visible page (taking the page rotation into account), x coordinates increasing to the right, y coordinates increasing downwards, and the units being the PDF default user space units (usually 1/72 inch).
In this coordinate system he needs to extract (horizontal or vertical) lines in the form of
coordinates of the left / top end point and
the width / height.
Transforming LineCatcher results
The helper class LineCatcher he got from Tilman, on the other hand, does not take page rotation into account. Furthermore, it returns the bottom end point for vertical lines, not the top end point. Thus, a coordinate transformation has to be applied to of the LineCatcher results.
For this simply replace
for(Rectangle2D rect:rectList) {
String pageNum = Integer.toString(n + 1);
String x = Double.toString(rect.getX());
String y = Double.toString(page_height - rect.getY()) ;
String w = Double.toString(rect.getWidth());
String h = Double.toString(rect.getHeight());
writeToFile(pageNum, x, y, w, h, osw);
}
by
int pageRotation = page.getRotation();
PDRectangle pageCropBox = page.getCropBox();
for(Rectangle2D rect:rectList) {
String pageNum = Integer.toString(n + 1);
String x, y, w, h;
switch(pageRotation) {
case 0:
x = Double.toString(rect.getX() - pageCropBox.getLowerLeftX());
y = Double.toString(pageCropBox.getUpperRightY() - rect.getY() + rect.getHeight());
w = Double.toString(rect.getWidth());
h = Double.toString(rect.getHeight());
break;
case 90:
x = Double.toString(rect.getY() - pageCropBox.getLowerLeftY());
y = Double.toString(rect.getX() - pageCropBox.getLowerLeftX());
w = Double.toString(rect.getHeight());
h = Double.toString(rect.getWidth());
break;
case 180:
x = Double.toString(pageCropBox.getUpperRightX() - rect.getX() - rect.getWidth());
y = Double.toString(rect.getY() - pageCropBox.getLowerLeftY());
w = Double.toString(rect.getWidth());
h = Double.toString(rect.getHeight());
break;
case 270:
x = Double.toString(pageCropBox.getUpperRightY() - rect.getY() + rect.getHeight());
y = Double.toString(pageCropBox.getUpperRightX() - rect.getX() - rect.getWidth());
w = Double.toString(rect.getHeight());
h = Double.toString(rect.getWidth());
break;
default:
throw new IOException(String.format("Unsupported page rotation %d on page %d.", pageRotation, page));
}
writeToFile(pageNum, x, y, w, h, osw);
}
(ExtractLinesWithDir test testExtractLineRotationTestWithDir)
Relation to TextPosition.get?DirAdj() coordinates
The OP describes the coordinates by referring to the TextPosition class methods getXDirAdj() and getYDirAdj(). Indeed, these methods return coordinates in a coordinate system with the origin in the upper left page corner and y coordinates increasing downwards after rotating the page so that the text is drawn upright.
In case of the example document all the text is drawn so that it is upright after applying the page rotation. From this my understanding of the requirement written at the top has been derived.
The problem with using the TextPosition.get?DirAdj() values as coordinates globally, though, is that in documents with pages with text drawn in different directions, the collected text coordinates suddenly are relative to different coordinate systems. Thus, a general solution should not collect coordinates wildly like that. Instead it should determine a page orientation at first (e.g. the orientation given by the page rotation or the orientation shared by most of the text) and use coordinates in the fixed coordinate system given by that orientation plus an indication of the writing direction of the text piece in question.

The method add(SimpleFeature) is undefined for the type SimpaleFeatureCollection

I am trying to implement one program for vectorization where I have following compile time error. I am using GeoTools 14.4.
private SimpleFeatureCollection assembleFeatures(GridCoverage2D grid, int band,
boolean insideEdges, SimpleFeatureType type, ProgressListener monitor) {
if (monitor == null) {
monitor = new NullProgressListener();
}
SimpleFeatureCollection features = FeatureCollections.newCollection();
SimpleFeatureBuilder builder = new SimpleFeatureBuilder(type);
Point2D p = new Point2D.Double();
double[] bandData = new double[grid.getNumSampleDimensions()];
polygonizer.add(lines);
Collection polygons = polygonizer.getPolygons();
final int size = polygons.size();
try {
float progressScale = 100.0f / size;
monitor.started();
int index = 0;
for (Iterator i = polygons.iterator(); i.hasNext(); index++) {
if (monitor.isCanceled()) {
throw new CancellationException();
}
monitor.progress(progressScale * index);
Polygon poly = (Polygon) i.next();
InteriorPointArea ipa = new InteriorPointArea(poly);
Coordinate c = ipa.getInteriorPoint();
Point insidePt = geomFactory.createPoint(c);
if (!poly.contains(insidePt)) {
// try another method to generate an interior point
boolean found = false;
for (Coordinate ringC : poly.getExteriorRing().getCoordinates()) {
c.x = ringC.x + cellWidthX / 2;
c.y = ringC.y;
insidePt = geomFactory.createPoint(c);
if (poly.contains(insidePt)) {
found = true;
break;
}
}
if (!found) {
throw new IllegalStateException("Can't locate interior point for polygon");
}
}
p.setLocation(c.x, c.y);
bandData = grid.evaluate(p, bandData);
if (!isOutside(bandData[band])) {
builder.add(poly);
if (insideEdges) {
builder.add(bandData[band]);
} else {
builder.add(INSIDE_FLAG_VALUE);
}
features.add(builder.buildFeature(null));
// here it gives error "The method add(SimpleFeature) is undefined for the type SimpaleFeatureCollection"
}
}
return features;
} finally {
monitor.complete();
}
}
The full source code is here
Actually I copied 2 classes RasterToVectorFactory.java and RasterToVectorProcess.java and the rest is my GeoTiff 14.4 Code where I have below error.
The method add(SimpleFeature) is undefined for the type SimpaleFeatureCollection
I tried using following code as a workaround.
But the author who provided code on his website says the code will not work!!
//features.add(builder.buildFeature(null));
//add
System.out.println("adding...");
SimpleFeature feature = builder.buildFeature(null);
((Collection<SimpleFeature>) features).add(feature);
Change declaration of SimpleFeatureCollection to DefaultFeatureCollection class
DefaultFeatureCollection features = new DefaultFeatureCollection("your_id",type);

Octave dfdp.m for JAVA

I want to implement Levenberg Marquardt fitting in JAVA and found apache commons math suitable. Since I want to fit a function, where I dont have the derivative to calculate the gradient or Jacobian, I need somthing like dfdp.m from GNU octave to calculate numerical derivatives. Has someone done this already?
I did it myself, in case someone else needs it here is the approach
dfdp.m code
m=size(x,1); if (m==1), m=size(x,2); end %# PAK: in case #cols > #rows
n=length(p); %dimensions
ps=p; prt=zeros(m,n);del=zeros(n,1); % initialise Jacobian to Zero
for j=1:n
del(j)=dp(j) .*p(j); %cal delx=fract(dp)*param value(p)
if p(j)==0
del(j)=dp(j); %if param=0 delx=fraction
end
p(j)=ps(j) + del(j);
if del(j)~=0, f1=feval(func,x,p); %FJ ~= not equal (!=) ...> p is now (p + dp*p)
if dp(j) < 0, prt(:,j)=(f1-f)./del(j);
else
p(j)=ps(j) - del(j); %FJ ...> p is now (p - dp*p)
prt(:,j)=(f1-feval(func,x,p))./(2 .*del(j)); %FJ 2 steps from (ps + del) to (ps - del)
end
end
p(j)=ps(j); %restore p(j)
end
JAVA code
private static class GhoosProblem {
private double[][] data;
private double[] dp;
public GhoosProblem(double[][] datapoints, double[] delta_p) {
data = datapoints;
//dp= fractional increment of p for numerical derivatives
//dp(j)>0 central differences calculated
//dp(j)<0 one sided differences calculated
//dp(j)=0 sets corresponding partials to zero; i.e. holds p(j) fixed
dp = delta_p;
}
public MultivariateVectorFunction getModelFunction() {
return new MultivariateVectorFunction() {
public double[] value(double[] params) {
double[] values = new double[data.length];
for (int i = 0; i < values.length; ++i) {
final double t = data[i][0]; // get the double value
values[i] = params[0] *
Math.pow(t, params[2]) *
Math.exp(-params[1] * t); // Ghoos function
}
return values; // function values
}
};
}
public MultivariateMatrixFunction getModelFunctionJacobian2() {
return new MultivariateMatrixFunction() {
public double[][] value(double[] params) {
double[][] jacobian = new double[data.length][params.length];
final double a = params[0];
final double b = params[2];
final double c = params[1];
for (int i = 0; i < jacobian.length; ++i) {
final double t = data[i][0]; // get the double value
jacobian[i][0] = Math.pow(t, b) * Math.exp(-c*t);
jacobian[i][2] = a * Math.exp(-c*t) * Math.pow(t, b) * Math.log(t);
jacobian[i][1] = a * Math.pow(t, b) * (-t*Math.exp(-c*t));
}
//System.out.println("Jacobian= "+ Arrays.deepToString(jacobian));
return jacobian;
}
};
}
// compared to Ge2.m octave
public MultivariateMatrixFunction getModelFunctionJacobian() {
return new MultivariateMatrixFunction() {
public double[][] value(double[] params) {
int m = data.length; // cols
int n = params.length; // rows
double[] p = params;
double[] ps = params;
double[] del = new double[n];
double[] f = new double[n];
double[] f1 = new double[n];
BlockRealMatrix prt = new BlockRealMatrix(m, n); // initializes to zeros
f=feval(p);
for (int j=0; j<n; ++j) {
del[j]=dp[j] * p[j]; //delta_x=fractional(dp) * param value(p)
if (p[j]==0)
del[j]=dp[j]; //if param=0 delta_x=fractional(dp)
p[j]=ps[j] + del[j];
if (del[j]!=0) {
f1=feval(p); //p is now (p + dp*p)
if (dp[j]<0)
prt.setColumn(j,(new ArrayRealVector(f1)).subtract(new ArrayRealVector(f)).mapDivideToSelf(del[j]).toArray()); // one sided diff
else {
p[j]=ps[j] - del[j]; // p is now (p - dp*p)
prt.setColumn(j,(new ArrayRealVector(f1)).subtract(new ArrayRealVector(feval(p))).mapDivideToSelf(2*del[j]).toArray()); // central diff
}
}
p[j]=ps[j]; //restore p(j)
}//for
//System.out.println("Jacobian= "+ Arrays.deepToString(prt.getData()));
return prt.getData(); //jacobian, dimension is (m x n)
}
};
}
public double[] feval(double[] params) {
double[] values = new double[data.length];
for (int i = 0; i < values.length; ++i) {
final double t = data[i][0]; // get the double value
values[i] = params[0] *
Math.pow(t, params[2]) *
Math.exp(-params[1] * t); // Ghoos function
}
return values;
}
}//GhoosProblem
sorry if idention of code did not come out nice!
the relevant part is the getModelFunctionJacobian() -Function
I have renamed the analytical derivatives part as getModelFunctionJacobian2(), and posted here for comparison
to complete with here is the levenberg marquardt setup to use the GhoosFunction
public void fit() {
final double[][] dataPoints = { // x, y
//{0.0/60, 0.0}, // never use {0, 0} => org.apache.commons.math3.exception.ConvergenceException: illegal state: unable to perform Q.R decomposition on the 17x3 jacobian matrix
{15.0/60, 8.891104},
{30.0/60, 13.21852},
{45.0/60, 28.09051},
{60.0/60, 43.0011},
{75.0/60, 57.43561},
{90.0/60, 67.06862},
{105.0/60, 82.60239},
{120.0/60, 72.4649},
{135.0/60, 61.4},
{150.0/60, 43.97924},
{165.0/60, 30.6},
{180.0/60, 20.77112},
{195.0/60, 15.5},
{210.0/60, 10.85442},
{225.0/60, 9.33},
{240.0/60, 7.260234},
};
final double[] initialGuess = { 1.0, 1.0, 1.0 }; // p
final double[] fract_change = { 1E-4, 1E-4, 1E-4 }; // dp should be below 0.0001
final GhoosProblem problem = new GhoosProblem(dataPoints, fract_change);
final int len = dataPoints.length;
final double[] weights = new double[len];
final double[] target = new double[len];
for (int i = 0; i < len; i++){
weights[i] = 1.0;// / dataPoints[i][1];
target[i] = dataPoints[i][1];
}
final LevenbergMarquardtOptimizer optimizer = new LevenbergMarquardtOptimizer()
.withCostRelativeTolerance(1E-4) // stol in octave
.withParameterRelativeTolerance(1E-4); // dp should be below 0.0001
final Optimum optimum = optimizer.optimize(
builder(problem)
.weight(new DiagonalMatrix(weights))
.target(target)
.start(initialGuess)
.maxIterations(100)
.build()
);
final RealVector solution = optimum.getPoint();
solution.setEntry(0, solution.getEntry(0) / 60.0); // go back to minutes
System.out.println("solution= " + solution);
System.out.println("CostRelativeTolerance= " + optimizer.getCostRelativeTolerance());
System.out.println("ParameterRelativeTolerance= " + optimizer.getParameterRelativeTolerance());
System.out.println("evaluations= " + optimum.getEvaluations());
System.out.println("iterations= " + optimum.getIterations());
//System.out.println("residuals= " + optimum.getResiduals());
System.out.println("RMS= " + optimum.getRMS());
System.out.println("sigma= " + optimum.getSigma(1E-10));
}//fit
public LeastSquaresBuilder builder(GhoosProblem problem){
return new LeastSquaresBuilder()
.checkerPair(new SimpleVectorValueChecker(1e-6, 1e-6)) // The SimpleVectorValueChecker Class (Simple implementation of the ConvergenceChecker) contains a method that uses the value of the function between two successive iterations of the optimisation algorithm to check if convergence has occured
.maxEvaluations(Integer.MAX_VALUE)
.maxIterations(Integer.MAX_VALUE)
//.lazyEvaluation(true)
.model(problem.getModelFunction(), problem.getModelFunctionJacobian());
}

How to combine 2 images to form hybrid image?

I am implementing hybrid image with ImageJ and stuck at merging low filter image and high filter image to form a hybrid image.
This is what I already done.I have 2 images from Gaussian Blur and Laplician of Gaussian filer. I need to merge these 2 images by layer after that. Any idea how to achieve it?
import ij.*;
import ij.process.*;
import ij.gui.*;
import java.awt.*;
import ij.plugin.filter.*;
import ij.plugin.*;
import ij.io.*;
import java.io.*;
public class HybridImage_Plugin implements PlugInFilter{
int cfsize=3;
String img_lowPass;
String img_highPass;
private double[][] filter;
private double sigma;
float w=2 ,delta=0 , thr=0;
int mode=0;
//dialogbox
private boolean GUI()
{
GenericDialog gd = new GenericDialog("Enter Values", IJ.getInstance());
gd.addNumericField("Sigma (3,5,9,17,35)", cfsize, 0);
gd.addStringField("Low-Pass", "/home/atrx/ImageJ/plugins/hybridimage/l1.tif");
gd.addStringField("High-Pass", "/home/atrx/ImageJ/plugins/hybridimage/l2.tif");
return getUserParams(gd);
}
//get parameters
private boolean getUserParams(GenericDialog gd)
{
gd.showDialog();
if (gd.wasCanceled())
{
return false;
}
cfsize = (int) gd.getNextNumber();
img_lowPass = gd.getNextString();
img_highPass= gd.getNextString();
return true;
}
public int setup(String arg, ImagePlus imp) {
return PlugInFilter.NO_IMAGE_REQUIRED;
}
public void run(ImageProcessor ip) {
int[][] result;
if(GUI() == false)
{
return;
}
else
{
Opener opener1 = new Opener();
Opener opener2 = new Opener();
ImagePlus imp1= opener1.openImage(img_lowPass);
ImagePlus imp2= opener2.openImage(img_highPass);
//imp1.show("Low Pass Image");
//imp2.show("HighPass Image");
ImageProcessor ip1 = imp1.getProcessor();
ImageProcessor ip2 = imp2.getProcessor();
//lowpass filter(Gaussian Blur)
ip1.blurGaussian(cfsize);
showProcessor(ip1,"Low Pass Filtered Image");
//highpass filter(LoG)
int csize = ip2.getHeight();
int rsize = ip2.getWidth();
Rectangle rect = ip2.getRoi();
int d0,a0,acr,dow,it;
int i,x,y;
double h12, h21, ft, h1h2, h2h1, fmu, dh, dv;
double r, dt, dmx, dmn;
float logaus[] = new float[(rect.width>rect.height)? rect.width : rect.height];
float gaus[] = new float[(rect.width>rect.height)? rect.width : rect.height];
float dgaus[] = new float[(rect.width>rect.height)? rect.width : rect.height];
long zcn =0;
byte pixels[] = (byte[])ip2.getPixels();
int img_in[] = new int[rect.width*rect.height];
if (cfsize<0) cfsize=3;
if (cfsize>35) cfsize=35;
if(w<0) w=0;
int fsize = (int)(cfsize*w);
if (fsize%2 == 0)
{
fsize += 1;
}
double dimg[] = new double[rect.height*rect.width];
double dr[] = new double[rect.height*rect.width];
i=0;
for(y=rect.y;y<(rect.y+rect.height);y++)
{
for(x=rect.x;x<(rect.x+rect.width);x++)
{
img_in[i] = (pixels[(y*rsize)+x]&0xff);
i++;
}
}
int size = rect.width + fsize -1;
int image[] = new int[(rect.width+fsize-1)*(rect.height+fsize-1)];
int extension= (fsize/2);
for( i=0; i<rect.height;i++)
{
System.arraycopy(img_in,(i*rect.width),image,( ((i+extension)*(rect.width+fsize-1))+ extension ),rect.width);
}
h1h2= h2h1 = h12 =0.0;
for(i=1; i<( (fsize+1) /2);i++)
{
w = (float)cfsize/(float)2.0/(float)1.414;
ft = i/w;
gaus[i] = (float)Math.exp(-ft*ft/2);
h1h2 += 2.0 *(gaus[i]);
logaus[i] =(float)(1-ft*ft)*(float)Math.exp(-ft*ft/2);
h2h1 += 2.0*(logaus[i]);
dgaus[i] =(float)ft*(float)Math.exp(-ft*ft/2);
}
fmu = (h2h1 + 1)* (h1h2+1);
int prel[] = new int[rect.width+1];
dmx = -99999.9;
dmn = 99999.9;
int limit = ((rect.width+fsize-1)*(rect.height+fsize-1));
for(d0=0;d0<rect.height;d0++)
{
for(a0=0;a0<rect.width;a0++)
{
acr = a0 + fsize/2;
dow = d0 + fsize/2;
dh = dv = 0.0;
h1h2 = h2h1 = 0.0;
for (int j=1; j<(fsize+1)/2; j++)
{
int a0d0, a0d1, a1d0, a1d1;
h12=h21=0.0;
for(i=1;i<(fsize+1)/2;i++)
{
a0d0 = acr-i+((dow-j)*size);
a0d1 = acr-i+((dow+j)*size);
a1d0 = acr+i+((dow-j)*size);
a1d1 = acr+i+((dow+j)*size);
h12 += logaus[i]*(image[a0d0] + image[a0d1]+
image[a1d0] + image[a1d1]);
h21 += gaus[i]* (image[a0d0] + image[a0d1] +
image[a1d0] + image[a1d1]);
}
a0d0 = acr-j+dow*size;
a0d1 = acr+(dow-j)*size;
a1d0 = acr+j+dow*size;
a1d1 = acr+(dow+j)*size;
h1h2 += gaus[j] * (h12+ image[a0d0]+image[a0d1]+
image[a1d0]+image[a1d1]);
h2h1 += logaus[j]*(h21+ image[a0d0]+ image[a0d1] +
image[a1d0] + image[a1d1] );
if(thr != 0.0)
{
dh += dgaus[j] * ( image[a1d0] - image[a0d0] );
dv += dgaus[j] * ( image[a1d1] - image[a0d1] );
}
}
dt = dimg[d0*rect.width+a0] = h1h2 + h2h1 + (2*image[dow*size+acr]) ;
if (dt > dmx) dmx = dt;
if (dt < dmn) dmn = dt;
if( thr!= 0.0)
{
dr[(d0*rect.width)+a0] = Math.abs(dh) + Math.abs(dv);
}
}
}
dmx = (dmx-dmn) / 2;
dmn += dmx;
int row=0, column=0;
for(d0=0;d0<rect.height;d0++)
{
for(a0=0;a0<rect.width;a0++)
{
int id = (d0*rect.width) +a0;
int index = rsize*(rect.y+d0) + (a0+rect.x);
int k = 15;
it = (int)(dt = (dimg[id] - (dmn-delta*dmx))*255 / (dmx*(1+Math.abs(delta))));
switch(mode){
case 0:
pixels[index] = (byte)((dt-dmn+dmx)/dmx*127);
break;
case 1:
pixels[index] = (byte)Math.abs(it);
break;
case 2:
pixels[index] = (byte)( ((dt!=0)?((dt>0) ? 1: -1) : 0) * 192);
break;
case 3:
default:
r = dr[id];
it = ( (dt!=0) ? ((dt>0) ? 1: -1) : 0);
if( it==0 && r>=thr)
{
k = 255;
zcn++;
}
else
{
if( (it*prel[a0]<0 || it*prel[a0+1]<0) && r>=thr)
{
k = 255;
zcn++;
}
}
prel[a0+1] = it;
if(k==255 || mode!=3)
pixels[index] = (byte)k;
break;
}
}
}
showProcessor(ip2,"High Pass Filtered Image");
}
}
static void showProcessor(ImageProcessor ip, String title){
ImagePlus win = new ImagePlus(title,ip);
win.show();
}
}
Have you tried performing a weighted sum?
OUT = w*LPF + (1 - w)*HPF
This kind of sum is used everywhere. In particular, image blending, alpha matting and even in some optimization schemes.
However because there are patches of varying spatial frequencies all around your image, you may have to make the weight adaptive. You also have to choose which one you want to emphasize more. Do you want the low pass or high pass information to stand out more? Depending on which you want, you might want to use information in either one of those images and run it through some distance or similarity measure to get the right weight.

Categories

Resources