CSJ2K.j2k.entropy.encoder.EBCOTRateAllocator.optimizeBitstreamLayer C# (CSharp) 메소드

optimizeBitstreamLayer() 개인적인 메소드

This function implements the rate-distortion optimization algorithm. It saves the state of any previously generated bit-stream layers and then simulate the formation of a new layer in the bit stream as often as necessary to find the smallest rate-distortion threshold such that the total number of bytes required to represent the layer does not exceed `maxBytes' minus `prevBytes'. It then restores the state of any previously generated bit-stream layers and returns the threshold.
private optimizeBitstreamLayer ( int layerIdx, float fmaxt, int maxBytes, int prevBytes ) : float
layerIdx int The index of the current layer /// ///
fmaxt float The maximum admissible slope value. Normally the threshold /// slope of the previous layer. /// ///
maxBytes int The maximum number of bytes that can be written. It /// includes the length of the current layer bistream length and all the /// previous layers bit streams. /// ///
prevBytes int The number of bytes of all the previous layers. /// ///
리턴 float
        private float optimizeBitstreamLayer(int layerIdx, float fmaxt, int maxBytes, int prevBytes)
        {
            int nt; // The total number of tiles
            int nc; // The total number of components
            int numLvls; // The total number of resolution levels
            int actualBytes; // Actual number of bytes for a layer
            float fmint; // Minimum of the current threshold interval
            float ft; // Current threshold
            SubbandAn sb; // Current subband
            BitOutputBuffer hBuff; // The packet head buffer
            byte[] bBuff; // The packet body buffer
            int sidx; // The index in the summary table
            bool sopUsed; // Should SOP markers be used ?
            bool ephUsed; // Should EPH markers be used ?
            //int precinctIdx; // Precinct index for current packet
            int nPrec; // Number of precincts in the current resolution level

            // Save the packet encoder state
            pktEnc.save();

            nt = src.getNumTiles();
            nc = src.NumComps;
            hBuff = null;
            bBuff = null;

            // Estimate the minimum slope to start with from the summary
            // information in 'RDSlopesRates'. This is a real minimum since it
            // does not include the packet head overhead, which is always
            // non-zero.

            // Look for the summary entry that gives 'maxBytes' or more data
            for (sidx = RD_SUMMARY_SIZE - 1; sidx > 0; sidx--)
            {
                if (RDSlopesRates[sidx] >= maxBytes)
                {
                    break;
                }
            }
            // Get the corresponding minimum slope
            fmint = getSlopeFromSIndex(sidx);
            // Ensure that it is smaller the maximum slope
            if (fmint >= fmaxt)
            {
                sidx--;
                fmint = getSlopeFromSIndex(sidx);
            }
            // If we are using the last entry of the summary, then that
            // corresponds to all the data, Thus, set the minimum slope to 0.
            if (sidx <= 0)
                fmint = 0;

            // We look for the best threshold 'ft', which is the lowest threshold
            // that generates no more than 'maxBytes' code bytes.

            // The search is done iteratively using a binary split algorithm. We
            // start with 'fmaxt' as the maximum possible threshold, and 'fmint'
            // as the minimum threshold. The threshold 'ft' is calculated as the
            // middle point of 'fmaxt'-'fmint' interval. The 'fmaxt' or 'fmint'
            // bounds are moved according to the number of bytes obtained from a
            // simulation, where 'ft' is used as the threshold.

            // We stop whenever the interval is sufficiently small, and thus
            // enough precision is achieved.

            // Initialize threshold as the middle point of the interval.
            ft = (fmaxt + fmint) / 2f;
            // If 'ft' reaches 'fmint' it means that 'fmaxt' and 'fmint' are so
            // close that the average is 'fmint', due to rounding. Force it to
            // 'fmaxt' instead, since 'fmint' is normally an exclusive lower
            // bound.
            if (ft <= fmint)
                ft = fmaxt;

            do
            {
                // Get the number of bytes used by this layer, if 'ft' is the
                // threshold, by simulation.
                actualBytes = prevBytes;
                src.setTile(0, 0);

                for (int t = 0; t < nt; t++)
                {
                    for (int c = 0; c < nc; c++)
                    {
                        // set boolean sopUsed here (SOP markers)
                        sopUsed = ((System.String) encSpec.sops.getTileDef(t)).ToUpper().Equals("on".ToUpper());
                        // set boolean ephUsed here (EPH markers)
                        ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).ToUpper().Equals("on".ToUpper());

                        // Get LL subband
                        sb = (SubbandAn) src.getAnSubbandTree(t, c);
                        numLvls = sb.resLvl + 1;
                        sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
                        //loop on resolution levels
                        for (int r = 0; r < numLvls; r++)
                        {

                            nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y;
                            for (int p = 0; p < nPrec; p++)
                            {

                                findTruncIndices(layerIdx, c, r, t, sb, ft, p);
                                hBuff = pktEnc.encodePacket(layerIdx + 1, c, r, t, cblks[t][c][r], truncIdxs[t][layerIdx][c][r], hBuff, bBuff, p);

                                if (pktEnc.PacketWritable)
                                {
                                    bBuff = pktEnc.LastBodyBuf;
                                    actualBytes += bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, true, sopUsed, ephUsed);
                                    actualBytes += bsWriter.writePacketBody(bBuff, pktEnc.LastBodyLen, true, pktEnc.ROIinPkt, pktEnc.ROILen);
                                }
                            } // end loop on precincts
                            sb = sb.parentband;
                        } // End loop on resolution levels
                    } // End loop on components
                } // End loop on tiles

                // Move the interval bounds according to simulation result
                if (actualBytes > maxBytes)
                {
                    // 'ft' is too low and generates too many bytes, make it the
                    // new minimum.
                    fmint = ft;
                }
                else
                {
                    // 'ft' is too high and does not generate as many bytes as we
                    // are allowed too, make it the new maximum.
                    fmaxt = ft;
                }

                // Update 'ft' for the new iteration as the middle point of the
                // new interval.
                ft = (fmaxt + fmint) / 2f;
                // If 'ft' reaches 'fmint' it means that 'fmaxt' and 'fmint' are
                // so close that the average is 'fmint', due to rounding. Force it
                // to 'fmaxt' instead, since 'fmint' is normally an exclusive
                // lower bound.
                if (ft <= fmint)
                    ft = fmaxt;

                // Restore previous packet encoder state
                pktEnc.restore();

                // We continue to iterate, until the threshold reaches the upper
                // limit of the interval, within a FLOAT_REL_PRECISION relative
                // tolerance, or a FLOAT_ABS_PRECISION absolute tolerance. This is
                // the sign that the interval is sufficiently small.
            }
            while (ft < fmaxt * (1f - FLOAT_REL_PRECISION) && ft < (fmaxt - FLOAT_ABS_PRECISION));

            // If we have a threshold which is close to 0, set it to 0 so that
            // everything is taken into the layer. This is to avoid not sending
            // some least significant bit-planes in the lossless case. We use the
            // FLOAT_ABS_PRECISION value as a measure of "close" to 0.
            if (ft <= FLOAT_ABS_PRECISION)
            {
                ft = 0f;
            }
            else
            {
                // Otherwise make the threshold 'fmaxt', just to be sure that we
                // will not send more bytes than allowed.
                ft = fmaxt;
            }
            return ft;
        }