001/* 002Copyright 2006 Jerry Huxtable 003 004Licensed under the Apache License, Version 2.0 (the "License"); 005you may not use this file except in compliance with the License. 006You may obtain a copy of the License at 007 008 http://www.apache.org/licenses/LICENSE-2.0 009 010Unless required by applicable law or agreed to in writing, software 011distributed under the License is distributed on an "AS IS" BASIS, 012WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013See the License for the specific language governing permissions and 014limitations under the License. 015*/ 016 017package com.jhlabs.image; 018 019import java.awt.*; 020import java.awt.image.*; 021 022/** 023 * A class which warps an image using a field Warp algorithm. 024 */ 025public class FieldWarpFilter extends TransformFilter { 026 027 public static class Line { 028 public int x1, y1, x2, y2; 029 public int dx, dy; 030 public float length, lengthSquared; 031 032 public Line(int x1, int y1, int x2, int y2) { 033 this.x1 = x1; 034 this.y1 = y1; 035 this.x2 = x2; 036 this.y2 = y2; 037 } 038 039 public void setup() { 040 dx = x2-x1; 041 dy = y2-y1; 042 lengthSquared = dx*dx + dy*dy; 043 length = (float)Math.sqrt(lengthSquared); 044 } 045 } 046 047 private float amount = 1.0f; 048 private float power = 1.0f; 049 private float strength = 2.0f; 050 private Line[] inLines; 051 private Line[] outLines; 052 private Line[] intermediateLines; 053 private float width, height; 054 055 public FieldWarpFilter() { 056 } 057 058 /** 059 * Set the amount of warp. 060 * @param amount the amount 061 * @min-value 0 062 * @max-value 1 063 * @see #getAmount 064 */ 065 public void setAmount(float amount) { 066 this.amount = amount; 067 } 068 069 /** 070 * Get the amount of warp. 071 * @return the amount 072 * @see #setAmount 073 */ 074 public float getAmount() { 075 return amount; 076 } 077 078 public void setPower(float power) { 079 this.power = power; 080 } 081 082 public float getPower() { 083 return power; 084 } 085 086 public void setStrength(float strength) { 087 this.strength = strength; 088 } 089 090 public float getStrength() { 091 return strength; 092 } 093 094 public void setInLines( Line[] inLines ) { 095 this.inLines = inLines; 096 } 097 098 public Line[] getInLines() { 099 return inLines; 100 } 101 102 public void setOutLines( Line[] outLines ) { 103 this.outLines = outLines; 104 } 105 106 public Line[] getOutLines() { 107 return outLines; 108 } 109 110 protected void transform(int x, int y, Point out) { 111 } 112 113 protected void transformInverse(int x, int y, float[] out) { 114 float u = 0, v = 0; 115 float fraction = 0; 116 float distance; 117 float fdist; 118 float weight; 119 float a = 0.001f; 120 float b = 1.5f*strength + 0.5f; 121 float p = power; 122 123 float totalWeight = 0.0f; 124 float sumX = 0.0f; 125 float sumY = 0.0f; 126 127 for (int line = 0; line < inLines.length; line++) { 128 Line l1 = inLines[line]; 129 Line l = intermediateLines[line]; 130 float dx = x - l.x1; 131 float dy = y - l.y1; 132 133 fraction = (dx * l.dx + dy * l.dy) / l.lengthSquared; 134 fdist = (dy * l.dx - dx * l.dy) / l.length; 135 if (fraction <= 0) 136 distance = (float)Math.sqrt(dx*dx + dy*dy); 137 else if (fraction >= 1) { 138 dx = x - l.x2; 139 dy = y - l.y2; 140 distance = (float)Math.sqrt(dx*dx + dy*dy); 141 } else if (fdist >= 0) 142 distance = fdist; 143 else 144 distance = -fdist; 145 u = l1.x1 + fraction * l1.dx - fdist * l1.dy / l1.length; 146 v = l1.y1 + fraction * l1.dy + fdist * l1.dx / l1.length; 147 148 weight = (float)Math.pow(Math.pow(l.length, p) / (a + distance), b); 149 150 sumX += (u - x) * weight; 151 sumY += (v - y) * weight; 152//if (x % 10 == 0&&y == 20)System.out.println("distance="+distance+" weight="+weight+" sumX="+sumX+" sumY="+sumY+" u="+u+" v="+v); 153 totalWeight += weight; 154 } 155 156// out[0] = ImageMath.clamp(x + sumX / totalWeight + 0.5f, 0, width-1); 157// out[1] = ImageMath.clamp(y + sumY / totalWeight + 0.5f, 0, height-1); 158 out[0] = x + sumX / totalWeight + 0.5f; 159 out[1] = y + sumY / totalWeight + 0.5f; 160 } 161 162 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 163 this.width = width; 164 this.height = height; 165 if ( inLines != null && outLines != null ) { 166 intermediateLines = new Line[inLines.length]; 167 for (int line = 0; line < inLines.length; line++) { 168 Line l = intermediateLines[line] = new Line( 169 ImageMath.lerp(amount, inLines[line].x1, outLines[line].x1), 170 ImageMath.lerp(amount, inLines[line].y1, outLines[line].y1), 171 ImageMath.lerp(amount, inLines[line].x2, outLines[line].x2), 172 ImageMath.lerp(amount, inLines[line].y2, outLines[line].y2) 173 ); 174 l.setup(); 175 inLines[line].setup(); 176 } 177 dst = super.filter( src, dst ); 178 intermediateLines = null; 179 return dst; 180 } 181 return src; 182 } 183 184 public String toString() { 185 return "Distort/Field Warp..."; 186 } 187 188}