/// <summary> Creates the top-level node and the entire subband tree, with the /// top-level dimensions, the number of decompositions, and the /// decomposition tree as specified. /// /// <p>This constructor just calls the same constructor of the super class, /// and then calculates the L2-norm (or energy weight) of each leaf.</p> /// /// <p>This constructor does not initialize the value of the magBits or /// stepWMSE member variables. This variables are normally initialized by /// the quantizer (see Quantizer).</p> /// /// </summary> /// <param name="w">The top-level width /// /// </param> /// <param name="h">The top-level height /// /// </param> /// <param name="ulcx">The horizontal coordinate of the upper-left corner with /// respect to the canvas origin, in the component grid. /// /// </param> /// <param name="ulcy">The vertical coordinate of the upper-left corner with /// respect to the canvas origin, in the component grid. /// /// </param> /// <param name="lvls">The number of levels (or LL decompositions) in the tree. /// /// </param> /// <param name="hfilters">The horizontal wavelet analysis filters for each /// resolution level, starting at resolution level 0. /// /// </param> /// <param name="vfilters">The vertical wavelet analysis filters for each /// resolution level, starting at resolution level 0. /// /// </param> /// <seealso cref="Subband.Subband(int,int,int,int,int,"> /// WaveletFilter[],WaveletFilter[]) /// /// </seealso> /// <seealso cref="jj2000.j2k.quantization.quantizer.Quantizer"> /// /// </seealso> public SubbandAn(int w, int h, int ulcx, int ulcy, int lvls, WaveletFilter[] hfilters, WaveletFilter[] vfilters) : base(w, h, ulcx, ulcy, lvls, hfilters, vfilters) { // Caculate the L2-norms calcL2Norms(); }
/// <summary> Splits the current subband in its four subbands. It changes the status /// of this element (from a leaf to a node, and sets the filters), creates /// the childs and initializes them. An IllegalArgumentException is thrown /// if this subband is not a leaf. /// /// <p>It uses the initChilds() method to initialize the childs.</p> /// /// </summary> /// <param name="hfilter">The horizontal wavelet filter used to decompose this /// subband. It has to be a AnWTFilter object. /// /// </param> /// <param name="vfilter">The vertical wavelet filter used to decompose this /// subband. It has to be a AnWTFilter object. /// /// </param> /// <returns> A reference to the LL leaf (subb_LL). /// /// </returns> /// <seealso cref="Subband.initChilds"> /// /// </seealso> protected internal override Subband split(WaveletFilter hfilter, WaveletFilter vfilter) { // Test that this is a node if (isNode) { throw new System.ArgumentException(); } // Modify this element into a node and set the filters isNode = true; this.hFilter = (AnWTFilter) hfilter; this.vFilter = (AnWTFilter) vfilter; // Create childs subb_LL = new SubbandAn(); subb_LH = new SubbandAn(); subb_HL = new SubbandAn(); subb_HH = new SubbandAn(); // Assign parent subb_LL.parentband = this; subb_HL.parentband = this; subb_LH.parentband = this; subb_HH.parentband = this; // Initialize childs initChilds(); // Return reference to LL subband return subb_LL; }
/// <summary> This function decomposes the mask for a node in the subband tree. /// after the mask is decomposed for a node, this function is called for /// the children of the subband. The decomposition is done line by line /// and column by column /// /// </summary> /// <param name="sb">The subband that is to be used for the decomposition /// /// </param> /// <param name="tilew">The width of the current tile /// /// </param> /// <param name="tileh">The height of the current tile /// /// </param> /// <param name="c">component number /// </param> private void decomp(Subband sb, int tilew, int tileh, int c) { int ulx = sb.ulx; int uly = sb.uly; int w = sb.w; int h = sb.h; int scalVal, maxVal = 0; int j, k, s, mi = 0, pin; // i, hi, li removed int hmax, lmax; // smax removed int lineoffs; // wrap, lastlow removed int[] mask = roiMask[c]; // local copy int[] low = maskLineLow; // local copy int[] high = maskLineHigh; // local copy int[] padLine = paddedMaskLine; // local copy int highFirst = 0; int lastpin; if (!sb.isNode) { return; } // HORIZONTAL DECOMPOSITION // Calculate number of high and low samples after decomposition // and get support for low and high filters WaveletFilter filter = sb.HorWFilter; int lnSup = filter.SynLowNegSupport; int hnSup = filter.SynHighNegSupport; int lpSup = filter.SynLowPosSupport; int hpSup = filter.SynHighPosSupport; int lsup = lnSup + lpSup + 1; int hsup = hnSup + hpSup + 1; // Calculate number of high/low coeffis in subbands highFirst = sb.ulcx % 2; if (sb.w % 2 == 0) { lmax = w / 2 - 1; hmax = lmax; } else { if (highFirst == 0) { lmax = (w + 1) / 2 - 1; hmax = w / 2 - 1; } else { hmax = (w + 1) / 2 - 1; lmax = w / 2 - 1; } } int maxnSup = (lnSup > hnSup)?lnSup:hnSup; // Maximum negative support int maxpSup = (lpSup > hpSup)?lpSup:hpSup; // Maximum positive support // Set padding to 0 for (pin = maxnSup - 1; pin >= 0; pin--) { padLine[pin] = 0; } for (pin = maxnSup + w - 1 + maxpSup; pin >= w; pin--) { padLine[pin] = 0; } // Do decomposition of all lines lineoffs = (uly + h) * tilew + ulx + w - 1; for (j = h - 1; j >= 0; j--) { lineoffs -= tilew; // Get the line to transform from the mask mi = lineoffs; for (k = w, pin = w - 1 + maxnSup; k > 0; k--, mi--, pin--) { padLine[pin] = mask[mi]; } lastpin = maxnSup + highFirst + 2 * lmax + lpSup; for (k = lmax; k >= 0; k--, lastpin -= 2) { // Low frequency samples pin = lastpin; for (s = lsup; s > 0; s--, pin--) { scalVal = padLine[pin]; if (scalVal > maxVal) { maxVal = scalVal; } } low[k] = maxVal; maxVal = 0; } lastpin = maxnSup - highFirst + 2 * hmax + 1 + hpSup; for (k = hmax; k >= 0; k--, lastpin -= 2) { // High frequency samples pin = lastpin; for (s = hsup; s > 0; s--, pin--) { scalVal = padLine[pin]; if (scalVal > maxVal) { maxVal = scalVal; } } high[k] = maxVal; maxVal = 0; } // Put the lows and highs back mi = lineoffs; for (k = hmax; k >= 0; k--, mi--) { mask[mi] = high[k]; } for (k = lmax; k >= 0; k--, mi--) { mask[mi] = low[k]; } } // VERTICAL DECOMPOSITION // Calculate number of high and low samples after decomposition // and get support for low and high filters filter = sb.VerWFilter; lnSup = filter.SynLowNegSupport; hnSup = filter.SynHighNegSupport; lpSup = filter.SynLowPosSupport; hpSup = filter.SynHighPosSupport; lsup = lnSup + lpSup + 1; hsup = hnSup + hpSup + 1; // Calculate number of high/low coeffs in subbands highFirst = sb.ulcy % 2; if (sb.h % 2 == 0) { lmax = h / 2 - 1; hmax = lmax; } else { if (sb.ulcy % 2 == 0) { lmax = (h + 1) / 2 - 1; hmax = h / 2 - 1; } else { hmax = (h + 1) / 2 - 1; lmax = h / 2 - 1; } } maxnSup = (lnSup > hnSup)?lnSup:hnSup; // Maximum negative support maxpSup = (lpSup > hpSup)?lpSup:hpSup; // Maximum positive support // Set padding to 0 for (pin = maxnSup - 1; pin >= 0; pin--) { padLine[pin] = 0; } for (pin = maxnSup + h - 1 + maxpSup; pin >= h; pin--) { padLine[pin] = 0; } // Do decomposition of all columns lineoffs = (uly + h - 1) * tilew + ulx + w; for (j = w - 1; j >= 0; j--) { lineoffs--; // Get the line to transform from the mask mi = lineoffs; for (k = h, pin = k - 1 + maxnSup; k > 0; k--, mi -= tilew, pin--) { padLine[pin] = mask[mi]; } lastpin = maxnSup + highFirst + 2 * lmax + lpSup; for (k = lmax; k >= 0; k--, lastpin -= 2) { // Low frequency samples pin = lastpin; for (s = lsup; s > 0; s--, pin--) { scalVal = padLine[pin]; if (scalVal > maxVal) { maxVal = scalVal; } } low[k] = maxVal; maxVal = 0; } lastpin = maxnSup - highFirst + 2 * hmax + 1 + hpSup; for (k = hmax; k >= 0; k--, lastpin -= 2) { // High frequency samples pin = lastpin; for (s = hsup; s > 0; s--, pin--) { scalVal = padLine[pin]; if (scalVal > maxVal) { maxVal = scalVal; } } high[k] = maxVal; maxVal = 0; } // Put the lows and highs back mi = lineoffs; for (k = hmax; k >= 0; k--, mi -= tilew) { mask[mi] = high[k]; } for (k = lmax; k >= 0; k--, mi -= tilew) { mask[mi] = low[k]; } } if (sb.isNode) { decomp(sb.HH, tilew, tileh, c); decomp(sb.LH, tilew, tileh, c); decomp(sb.HL, tilew, tileh, c); decomp(sb.LL, tilew, tileh, c); } }
/// <summary> Creates the top-level node and the entire subband tree, with the /// top-level dimensions, the number of decompositions, and the /// decomposition tree as specified. /// /// <p>This constructor just calls the same constructor of the super /// class.</p> /// /// </summary> /// <param name="w">The top-level width /// /// </param> /// <param name="h">The top-level height /// /// </param> /// <param name="ulcx">The horizontal coordinate of the upper-left corner with /// respect to the canvas origin, in the component grid. /// /// </param> /// <param name="ulcy">The vertical coordinate of the upper-left corner with /// respect to the canvas origin, in the component grid. /// /// </param> /// <param name="lvls">The number of levels (or LL decompositions) in the tree. /// /// </param> /// <param name="hfilters">The horizontal wavelet synthesis filters for each /// resolution level, starting at resolution level 0. /// /// </param> /// <param name="vfilters">The vertical wavelet synthesis filters for each /// resolution level, starting at resolution level 0. /// /// </param> /// <seealso cref="Subband.Subband(int,int,int,int,int,"> /// WaveletFilter[],WaveletFilter[]) /// /// </seealso> public SubbandSyn(int w, int h, int ulcx, int ulcy, int lvls, WaveletFilter[] hfilters, WaveletFilter[] vfilters):base(w, h, ulcx, ulcy, lvls, hfilters, vfilters) { }
/// <summary> This function generates the ROI mask for one tile-component. /// /// <P> Once the mask is generated in the pixel domain. it is decomposed /// following the same decomposition scheme as the wavelet transform. /// /// </summary> /// <param name="sb">The root of the subband tree used in the decomposition /// /// </param> /// <param name="magbits">The max number of magnitude bits in any code-block /// /// </param> /// <param name="c">component number /// </param> public override void makeMask(Subband sb, int magbits, int c) { int[] mask; // local copy ROI[] rois = this.roi_array; // local copy int i, j, k, r, maxj; // mink, minj removed int lrx, lry; int x, y, w, h; int cx, cy, rad; int wrap; int curScalVal; int tileulx = sb.ulcx; int tileuly = sb.ulcy; int tilew = sb.w; int tileh = sb.h; int lineLen = (tilew > tileh)?tilew:tileh; // Make sure there is a sufficiently large mask buffer if (roiMask[c] == null || (roiMask[c].Length < (tilew * tileh))) { roiMask[c] = new int[tilew * tileh]; mask = roiMask[c]; } else { mask = roiMask[c]; for (i = tilew * tileh - 1; i >= 0; i--) { mask[i] = 0; } } // Make sure there are sufficiently large line buffers if (maskLineLow == null || (maskLineLow.Length < (lineLen + 1) / 2)) { maskLineLow = new int[(lineLen + 1) / 2]; } if (maskLineHigh == null || (maskLineHigh.Length < (lineLen + 1) / 2)) { maskLineHigh = new int[(lineLen + 1) / 2]; } roiInTile = false; // Generate ROIs in pixel domain: for (r = rois.Length - 1; r >= 0; r--) { if (rois[r].comp == c) { curScalVal = magbits; if (rois[r].arbShape) { ImgReaderPGM maskPGM = rois[r].maskPGM; // Local copy if ((src.ImgWidth != maskPGM.ImgWidth) || (src.ImgHeight != maskPGM.ImgHeight)) { throw new System.ArgumentException("Input image and" + " ROI mask must " + "have the same " + "size"); } x = src.ImgULX; y = src.ImgULY; lrx = x + src.ImgWidth - 1; lry = y + src.ImgHeight - 1; if ((x > tileulx + tilew) || (y > tileuly + tileh) || (lrx < tileulx) || (lry < tileuly)) { // Roi not in tile continue; } // Check bounds x -= tileulx; lrx -= tileulx; y -= tileuly; lry -= tileuly; int offx = 0; int offy = 0; if (x < 0) { offx = -x; x = 0; } if (y < 0) { offy = -y; y = 0; } w = (lrx > (tilew - 1))?tilew - x:lrx + 1 - x; h = (lry > (tileh - 1))?tileh - y:lry + 1 - y; // Get shape line by line to reduce memory DataBlkInt srcblk = new DataBlkInt(); int mDcOff = -ImgReaderPGM.DC_OFFSET; int nROIcoeff = 0; int[] src_data; srcblk.ulx = offx; srcblk.w = w; srcblk.h = 1; i = (y + h - 1) * tilew + x + w - 1; maxj = w; wrap = tilew - maxj; for (k = h; k > 0; k--) { srcblk.uly = offy + k - 1; srcblk = (DataBlkInt)maskPGM.getInternCompData(srcblk, 0); src_data = srcblk.DataInt; for (j = maxj; j > 0; j--, i--) { if (src_data[j - 1] != mDcOff) { mask[i] = curScalVal; nROIcoeff++; } } i -= wrap; } if (nROIcoeff != 0) { roiInTile = true; } } else if (rois[r].rect) { // Rectangular ROI x = rois[r].ulx; y = rois[r].uly; lrx = rois[r].w + x - 1; lry = rois[r].h + y - 1; if ((x > tileulx + tilew) || (y > tileuly + tileh) || (lrx < tileulx) || (lry < tileuly)) { // Roi not in tile continue; } roiInTile = true; // Check bounds x -= tileulx; lrx -= tileulx; y -= tileuly; lry -= tileuly; x = (x < 0)?0:x; y = (y < 0)?0:y; w = (lrx > (tilew - 1))?tilew - x:lrx + 1 - x; h = (lry > (tileh - 1))?tileh - y:lry + 1 - y; i = (y + h - 1) * tilew + x + w - 1; maxj = w; wrap = tilew - maxj; for (k = h; k > 0; k--) { for (j = maxj; j > 0; j--, i--) { mask[i] = curScalVal; } i -= wrap; } } else { // Non-rectangular ROI. So far only circular case cx = rois[r].x - tileulx; cy = rois[r].y - tileuly; rad = rois[r].r; i = tileh * tilew - 1; for (k = tileh - 1; k >= 0; k--) { for (j = tilew - 1; j >= 0; j--, i--) { if (((j - cx) * (j - cx) + (k - cy) * (k - cy) < rad * rad)) { mask[i] = curScalVal; roiInTile = true; } } } } } } // If wavelet transform is used if (sb.isNode) { // Decompose the mask according to the subband tree // Calculate size of padded line buffer WaveletFilter vFilter = sb.VerWFilter; WaveletFilter hFilter = sb.HorWFilter; int lvsup = vFilter.SynLowNegSupport + vFilter.SynLowPosSupport; int hvsup = vFilter.SynHighNegSupport + vFilter.SynHighPosSupport; int lhsup = hFilter.SynLowNegSupport + hFilter.SynLowPosSupport; int hhsup = hFilter.SynHighNegSupport + hFilter.SynHighPosSupport; lvsup = (lvsup > hvsup)?lvsup:hvsup; lhsup = (lhsup > hhsup)?lhsup:hhsup; lvsup = (lvsup > lhsup)?lvsup:lhsup; paddedMaskLine = new int[lineLen + lvsup]; if (roiInTile) { decomp(sb, tilew, tileh, c); } } }
/// <summary> Splits the current subband in its four subbands. This creates the four /// childs (LL, HL, LH and HH) and converts the leaf in a node. /// /// </summary> /// <param name="hfilter">The horizontal wavelet filter used to decompose this /// subband. /// /// </param> /// <param name="vfilter">The vertical wavelet filter used to decompose this /// subband. /// /// </param> /// <returns> A reference to the LL leaf (getLL()). /// /// </returns> protected internal abstract Subband split(WaveletFilter hfilter, WaveletFilter vfilter);
/// <summary> The constructor of the SubbandROIMask takes the dimensions of the /// subband as parameters. A tree of masks is generated from the subband /// sb. Each Subband contains the boundaries of each ROI. /// /// </summary> /// <param name="sb">The subband corresponding to this Subband Mask /// /// </param> /// <param name="ulxs">The upper left x coordinates of the ROIs /// /// </param> /// <param name="ulys">The upper left y coordinates of the ROIs /// /// </param> /// <param name="lrxs">The lower right x coordinates of the ROIs /// /// </param> /// <param name="lrys">The lower right y coordinates of the ROIs /// /// </param> /// <param name="lrys">The lower right y coordinates of the ROIs /// /// </param> /// <param name="nr">Number of ROIs that affect this tile /// /// </param> public SubbandRectROIMask(Subband sb, int[] ulxs, int[] ulys, int[] lrxs, int[] lrys, int nr) : base(sb.ulx, sb.uly, sb.w, sb.h) { this.ulxs = ulxs; this.ulys = ulys; this.lrxs = lrxs; this.lrys = lrys; int r; if (sb.isNode) { isNode = true; // determine odd/even - high/low filters int horEvenLow = sb.ulcx % 2; int verEvenLow = sb.ulcy % 2; // Get filter support lengths WaveletFilter hFilter = sb.HorWFilter; WaveletFilter vFilter = sb.VerWFilter; int hlnSup = hFilter.SynLowNegSupport; int hhnSup = hFilter.SynHighNegSupport; int hlpSup = hFilter.SynLowPosSupport; int hhpSup = hFilter.SynHighPosSupport; int vlnSup = vFilter.SynLowNegSupport; int vhnSup = vFilter.SynHighNegSupport; int vlpSup = vFilter.SynLowPosSupport; int vhpSup = vFilter.SynHighPosSupport; // Generate arrays for children int x, y; int[] lulxs = new int[nr]; int[] lulys = new int[nr]; int[] llrxs = new int[nr]; int[] llrys = new int[nr]; int[] hulxs = new int[nr]; int[] hulys = new int[nr]; int[] hlrxs = new int[nr]; int[] hlrys = new int[nr]; for (r = nr - 1; r >= 0; r--) { // For all ROI calculate ... // Upper left x for all children x = ulxs[r]; if (horEvenLow == 0) { lulxs[r] = (x + 1 - hlnSup) / 2; hulxs[r] = (x - hhnSup) / 2; } else { lulxs[r] = (x - hlnSup) / 2; hulxs[r] = (x + 1 - hhnSup) / 2; } // Upper left y for all children y = ulys[r]; if (verEvenLow == 0) { lulys[r] = (y + 1 - vlnSup) / 2; hulys[r] = (y - vhnSup) / 2; } else { lulys[r] = (y - vlnSup) / 2; hulys[r] = (y + 1 - vhnSup) / 2; } // lower right x for all children x = lrxs[r]; if (horEvenLow == 0) { llrxs[r] = (x + hlpSup) / 2; hlrxs[r] = (x - 1 + hhpSup) / 2; } else { llrxs[r] = (x - 1 + hlpSup) / 2; hlrxs[r] = (x + hhpSup) / 2; } // lower right y for all children y = lrys[r]; if (verEvenLow == 0) { llrys[r] = (y + vlpSup) / 2; hlrys[r] = (y - 1 + vhpSup) / 2; } else { llrys[r] = (y - 1 + vlpSup) / 2; hlrys[r] = (y + vhpSup) / 2; } } // Create children hh = new SubbandRectROIMask(sb.HH, hulxs, hulys, hlrxs, hlrys, nr); lh = new SubbandRectROIMask(sb.LH, lulxs, hulys, llrxs, hlrys, nr); hl = new SubbandRectROIMask(sb.HL, hulxs, lulys, hlrxs, llrys, nr); ll = new SubbandRectROIMask(sb.LL, lulxs, lulys, llrxs, llrys, nr); } }
/// <summary> Creates the top-level node and the entire subband tree, with the /// top-level dimensions, the number of decompositions, and the /// decomposition tree as specified. /// /// <p>For the analysis subband gain calculation it is assumed that /// analysis filters are normalized with a DC gain of 1 and a Nyquist gain /// of 2.</p> /// /// <p>This constructor does not initialize the value of the magBits member /// variable. This variable is normally initialized by the quantizer, on /// the encoder side, or the bit stream reader, on the decoder side.</p> /// /// </summary> /// <param name="w">The top-level width /// /// </param> /// <param name="h">The top-level height /// /// </param> /// <param name="ulcx">The horizontal coordinate of the upper-left corner with /// respect to the canvas origin, in the component grid. /// /// </param> /// <param name="ulcy">The vertical coordinate of the upper-left corner with /// respect to the canvas origin, in the component grid. /// /// </param> /// <param name="lvls">The number of levels (or LL decompositions) in the tree. /// /// </param> /// <param name="hfilters">The horizontal wavelet filters (analysis or synthesis) /// for each resolution level, starting at resolution level 0. If there are /// less elements in the array than there are resolution levels, the last /// element is used for the remaining resolution levels. /// /// </param> /// <param name="vfilters">The vertical wavelet filters (analysis or synthesis) /// for each resolution level, starting at resolution level 0. If there are /// less elements in the array than there are resolution levels, the last /// element is used for the remaining resolution levels. /// /// </param> /// <seealso cref="WaveletTransform"> /// /// </seealso> public Subband(int w, int h, int ulcx, int ulcy, int lvls, WaveletFilter[] hfilters, WaveletFilter[] vfilters) { int i, hi, vi; Subband cur; // The current subband // Initialize top-level node this.w = w; this.h = h; this.ulcx = ulcx; this.ulcy = ulcy; this.resLvl = lvls; // First create dyadic decomposition. cur = this; for (i = 0; i < lvls; i++) { hi = (cur.resLvl <= hfilters.Length)?cur.resLvl - 1:hfilters.Length - 1; vi = (cur.resLvl <= vfilters.Length)?cur.resLvl - 1:vfilters.Length - 1; cur = cur.split(hfilters[hi], vfilters[vi]); } }