DWT.OrthogonalFilters Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of image-forensics Show documentation
Show all versions of image-forensics Show documentation
A library of image forensics algorithms for tampering localization.
The newest version!
package DWT;
/**
* Author Mark Bishop; 2014
* License GNU v3;
* This class is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
/**
* The coefficients were gathered from various sources including:
* Wavelab Version 850
* Adapted Wavelet Analysis from Theory to Software, Victor Wickerhauser
* A Wavelet Tour of Signal Processing, The Sparse Way, 3rd ed., Stephane Mallet
*/
import java.util.ArrayList;
/**
* Class responsibility: Provide filters for several orthogonal wavelets.
*
*/
public class OrthogonalFilters {
/**
*
* @param H
* low pass filter for QMF pair
* @return high pass filter for QMF pair
*/
public static double[] getHighPass(double[] H) {
double sign = 1;
int n = H.length;
double[] G = new double[n];
for (int i = 0; i < n; i++) {
G[n - i - 1] = H[i] * sign;
sign *= -1;
}
return G;
}
/**
*
* @param wavelet To be explained
* @param order To be explained
* @return Low Pass filter for QMF pair
*/
static double[] getLowPass(Wavelet wavelet, int order) {
if (wavelet == Wavelet.Haar) {
double[] f = { .707106781186547, .707106781186547 };
return f;
}
if (wavelet == Wavelet.Daubechies) {
switch (order) {
case 4: { // (Wickerhauser)
double[] f = { .482962913144534160, .836516303737807940,
.224143868042013390, -.129409522551260370 };
return f;
}
case 6: {// (Wickerhauser)
double[] f = { 0.332670552950082630, 0.806891509311092550,
0.459877502118491540, -0.135011020010254580,
-0.0854412738820266580, 0.0352262918857095330 };
return f;
}
case 8: {// (Wickerhauser but order reversed)
double[] f = { 0.2303778133090, 0.7148465705530,
0.6308807679300, -0.02798376941700, -0.1870348117190,
0.03084138183700, 0.032883011667, -0.01059740178500 };
return f;
}
case 10: {// (Wickerhauser but order reversed)
double[] f = { 0.160102397974, 0.603829269797, 0.724308528438,
0.138428145901, -0.242294887066, -0.032244869585,
0.07757149384, -0.006241490213, -0.012580751999,
0.003335725285 };
return f;
}
case 12: {// (Wickerhauser but order reversed)
double[] f = { 0.11154074335, 0.494623890398, 0.751133908021,
0.315250351709, -0.226264693965, -0.129766867567,
0.097501605587, 0.02752286553, -0.031582039318,
0.000553842201, 0.004777257511, -0.001077301085 };
return f;
}
case 14: {// (Wickerhauser but order reversed)
double[] f = { 0.077852054085, 0.396539319482, 0.729132090846,
0.469782287405, -0.143906003929, -0.224036184994,
0.071309219267, 0.080612609151, -0.038029936935,
-0.016574541631, 0.012550998556, 0.000429577973,
-0.001801640704, 0.0003537138 };
return f;
}
case 16: {// (Wickerhauser but order reversed)
double[] f = { 0.054415842243, 0.312871590914, 0.675630736297,
0.585354683654, -0.015829105256, -0.284015542962,
0.000472484574, 0.12874742662, -0.017369301002,
-0.044088253931, 0.013981027917, 0.008746094047,
-0.004870352993, -0.000391740373, 0.000675449406,
-0.000117476784 };
return f;
}
case 18: {// (Wickerhauser but order reversed)
double[] f = { 0.038077947364, 0.243834674613, 0.60482312369,
0.657288078051, 0.133197385825, -0.293273783279,
-0.096840783223, 0.148540749338, 0.030725681479,
-0.067632829061, 0.000250947115, 0.022361662124,
-0.004723204758, -0.004281503682, 0.001847646883,
0.000230385764, -0.000251963189, 0.00003934732 };
return f;
}
case 20: {// Wavelab src
double[] f = { 0.026670057901, 0.188176800078, 0.527201188932,
0.688459039454, 0.281172343661, -0.249846424327,
-0.195946274377, 0.127369340336, 0.093057364604,
-0.071394147166, -0.029457536822, 0.033212674059,
0.003606553567, -0.010733175483, 0.001395351747,
0.001992405295, -0.000685856695, -0.000116466855,
0.00009358867, -0.000013264203 };
return f;
}
}
}
if (wavelet == Wavelet.Beylkin) { // 18 (Wickerhauser but order
// reversed)
double[] f = { 0.00064048532852124535, -0.00273603162625860610,
0.0014842347824723461, 0.01004041184463199,
-0.014365807968852611, -0.017460408696028829,
0.042916387274192273, 0.01967986604432212,
-0.088543630623924835, -0.0175207462665229649,
0.1555387318770938, 0.02690030880369032,
-0.26449723144638482, -0.1109275983482343,
0.44971825114946867, 0.69982521405660590,
0.42421536081296141, 0.099305765374353927 };
return f;
}
if (wavelet == Wavelet.Vaidyanathan) {// length = 24 // Wavelab src
double[] f = { -.000062906118, .000343631905, -.000453956620,
-.000944897136, .002843834547, .000708137504,
-.008839103409, .003153847056, .019687215010,
-.014853448005, -.035470398607, .038742619293,
.055892523691, -.077709750902, -.083928884366,
.131971661417, .135084227129, -.194450471766,
-.263494802488, .201612161775, .635601059872,
.572797793211, .250184129505, .045799334111 };
return f;
}
if (wavelet == Wavelet.Coiflet) {// Wavelab src
switch (order) {
case 6: {
double[] f = { .038580777748, -.126969125396, -.077161555496,
.607491641386, .745687558934, .226584265197 };
return f;
}
case 12: {
double[] f = { .016387336463, -.041464936782, -.067372554722,
.386110066823, .812723635450, .417005184424,
-.076488599078, -.059434418646, .023680171947,
.005611434819, -.001823208871, -.000720549445 };
;
return f;
}
case 18: {
double[] f = { -.003793512864, .007782596426, .023452696142,
-.065771911281, -.061123390003, .405176902410,
.793777222626, .428483476378, -.071799821619,
-.082301927106, .034555027573, .015880544864,
-.009007976137, -.002574517688, .001117518771,
.000466216960, -.000070983303, -.000034599773 };
return f;
}
case 24: {
double[] f = { .000892313668, -.001629492013, -.007346166328,
.016068943964, .026682300156, -.081266699680,
-.056077313316, .415308407030, .782238930920,
.434386056491, -.066627474263, -.096220442034,
.039334427123, .025082261845, -.015211731527,
-.005658286686, .003751436157, .001266561929,
-.000589020757, -.000259974552, .000062339034,
.000031229876, -.000003259680, -.000001784985 };
return f;
}
case 30: {
double[] f = { -.000212080863, .000358589677, .002178236305,
-.004159358782, -.010131117538, .023408156762,
.028168029062, -.091920010549, -.052043163216,
.421566206729, .774289603740, .437991626228,
-.062035963906, -.105574208706, .041289208741,
.032683574283, -.019761779012, -.009164231153,
.006764185419, .002433373209, -.001662863769,
-.000638131296, .000302259520, .000140541149,
-.000041340484, -.000021315014, .000003734597,
.000002063806, -.000000167408, -.000000095158 };
return f;
}
}
}
if (wavelet == Wavelet.Symmlet) {// Wavelab but normalized by 1/sqrt(2)
switch (order) {
case 4: {
double[] f = { -0.07576571478935668, -0.029635527645960395,
0.4976186676325629, 0.803738751805386,
0.29785779560560505, -0.09921954357695636,
-0.012603967262263831, 0.03222310060407815 };
return f;
}
case 5: {
double[] f = { 0.027333068345162827, 0.029519490926071618,
-0.039134249302581074, 0.19939753397698343,
0.7234076904037638, 0.6339789634569107,
0.01660210576442332, -0.17532808990809687,
-0.021101834024928552, 0.019538882735385715 };
return f;
}
case 6: {
double[] f = { 0.0154041093273385, 0.003490712084330607,
-0.11799011114841682, -0.04831174258600069,
0.49105594192766583, 0.7876411410288363,
0.3379294217282582, -0.07263752278660392,
-0.021060292512696543, 0.04472490177075063,
0.0017677118643983668, -0.007800708324765445 };
return f;
}
case 7: {
double[] f = { 0.00268181456811643, -0.0010473848889657486,
-0.01263630340315281, 0.0305155131659067,
0.06789269350159828, -0.049552834937041906,
0.01744125508711021, 0.5361019170907816,
0.7677643170045847, 0.28862963175098844,
-0.14004724044270553, -0.10780823770361868,
0.004010244871703328, 0.01026817670849701 };
return f;
}
case 8: {
double[] f = { 0.0018899503329009007, -3.0292051455166417E-4,
-0.014952258336793822, 0.0038087520140603582,
0.04913717967348071, -0.027219029916815855,
-0.05194583810787925, 0.36444189483598555,
0.77718575169981, 0.48135965125923963,
-0.06127335906791368, -0.1432942383510657,
0.0076074873252853755, 0.03169508781034778,
-5.4213233163559E-4, -0.0033824159513597117 };
return f;
}
case 9: {
double[] f = { 0.0010694900326524929, -4.7315449858729915E-4,
-0.010264064027672312, 0.00885926749350085,
0.062077789302687425, -0.018233770779803246,
-0.19155083129625178, 0.03527248803589115,
0.6173384491405931, 0.717897082763343,
0.23876091460712456, -0.054568958430509365,
5.834627463304675E-4, 0.03022487885795232,
-0.011528210207970613, -0.013271967781516928,
6.197808890541263E-4, 0.0014009155255699105 };
return f;
}
case 10: {
double[] f = { 7.70159808941683E-4, 9.563267076371025E-5,
-0.008641299274130404, -0.0014653825830396562,
0.045927239214146896, 0.011609893910541074,
-0.1594942788241296, -0.07088053579601779,
0.4716906667438779, 0.7695100368531889,
0.3838267611450017, -0.035536740298026795,
-0.03199005682146376, 0.049994972068686125,
0.005764912044344502, -0.02035493979968329,
-8.043589343685685E-4, 0.004593173582708373,
5.703608432707147E-5, -4.5932942045186415E-4 };
return f;
}
}
}
// Battle performs comparatively poorly using the coefficients below
// (sig figs?).
if (wavelet == Wavelet.Battle) {
switch (order) {
case 1: {
double[] f = { -0.000122686, -0.000224296, 0.000511636,
0.000923371, -0.002201945, -0.003883261, 0.009990599,
0.016974805, -0.051945337, -0.06910102, 0.39729643,
0.817645956, 0.39729643, -0.06910102, -0.051945337,
0.016974805, 0.009990599, -0.003883261, -0.002201945,
0.000923371, 0.000511636, -0.000224296, -0.000122686 };
return f;
}
case 3: {
double[] f = { 0.000146098, -0.000232304, -0.000285414,
0.000462093, 0.000559952, -0.000927187, -0.001103748,
0.00188212, 0.002186714, -0.003882426, -0.00435384,
0.008201477, 0.008685294, -0.017982291, -0.017176331,
0.042068328, 0.032080869, -0.110036987, -0.050201753,
0.433923147, 0.766130398, 0.433923147, -0.050201753,
-0.110036987, 0.032080869, 0.042068328, -0.017176331,
-0.017982291, 0.008685294, 0.008201477, -0.00435384,
-0.003882426, 0.002186714, 0.00188212, -0.001103748,
-0.000927187, 0.000559952, 0.000462093, -0.000285414,
-0.000232304, 0.000146098 };
return f;
}
}
}
double[] error = { 0 };
return error;
}
/**
*
* @param wavelet To be explained
* @return List of available orders for a given wavelet.
*/
public static ArrayList validParameters(Wavelet wavelet) {
ArrayList result = new ArrayList();
switch (wavelet) {
case Haar:
result.add(2);
break;
case Daubechies:
for (int i = 4; i <= 20; i += 2) {
result.add(i);
}
break;
case Beylkin:
result.add(18);
break;
case Vaidyanathan:
result.add(24);
break;
case Coiflet:
for (int i = 6; i <= 30; i += 6) {
result.add(i);
}
break;
case Symmlet:
for (int i = 4; i <= 10; i++) {
result.add(i);
}
break;
case Battle:
result.add(1);
result.add(3);
break;
}
return result;
}
/**
*
* @param parameter To be explained
* @param wavelet To be explained
* @param signalLength To be explained
* @return A list of valid scales for a given wavelet and signal length.
* @throws Exception
*/
public static ArrayList validScales(int parameter,
Wavelet wavelet, int signalLength) throws Exception {
ArrayList validScales = new ArrayList();
int hLength = OrthogonalFilters.getLowPass(wavelet, parameter).length;
if (hLength > signalLength) {
throw new Exception("The filter is longer than the signal.");
}
int log2SigLen = (int) (Math.log(signalLength) / Math.log(2));
int min = (int) (Math.log(hLength) / Math.log(2));
for (int i = min; i <= log2SigLen; i++) {
double t = Math.log(hLength);
if (t < min) {
validScales.add(i);
}
}
return validScales;
}
}
// Some descriptive narrative from the Wavelab project:
//
// Description
// The Haar filter (which could be considered a Daubechies-2) was the
// first wavelet, though not called as such, and is discontinuous.
//
// The Beylkin filter places roots for the frequency response function
// close to the Nyquist frequency on the real axis.
//
// The Coiflet filters are designed to give both the mother and father
// wavelets 2*Par vanishing moments; here Par may be one of 1,2,3,4 or 5.
//
// The Daubechies filters are minimal phase filters that generate wavelets
// which have a minimal support for a given number of vanishing moments.
// They are indexed by their length, Par, which may be one of
// 4,6,8,10,12,14,16,18 or 20. The number of vanishing moments is par/2.
//
// Symmlets are also wavelets within a minimum size support for a given
// number of vanishing moments, but they are as symmetrical as possible,
// as opposed to the Daubechies filters which are highly asymmetrical.
// They are indexed by Par, which specifies the number of vanishing
// moments and is equal to half the size of the support. It ranges
// from 4 to 10.
//
// The Vaidyanathan filter gives an exact reconstruction, but does not
// satisfy any moment condition. The filter has been optimized for
// speech coding.
//
// The Battle-Lemarie filter generate spline orthogonal wavelet basis.
// The order Par gives the degree of the spline. The number of
// vanishing moments is Par+1.
//
//