corrade-vassal – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | vero | 1 | /* |
2 | * CVS identifier: |
||
3 | * |
||
4 | * $Id: ROIScaler.java,v 1.11 2001/09/20 12:42:20 grosbois Exp $ |
||
5 | * |
||
6 | * Class: ROIScaler |
||
7 | * |
||
8 | * Description: This class takes care of the scaling of the |
||
9 | * samples |
||
10 | * |
||
11 | * |
||
12 | * |
||
13 | * COPYRIGHT: |
||
14 | * |
||
15 | * This software module was originally developed by Raphaël Grosbois and |
||
16 | * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel |
||
17 | * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David |
||
18 | * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research |
||
19 | * Centre France S.A) in the course of development of the JPEG2000 |
||
20 | * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This |
||
21 | * software module is an implementation of a part of the JPEG 2000 |
||
22 | * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio |
||
23 | * Systems AB and Canon Research Centre France S.A (collectively JJ2000 |
||
24 | * Partners) agree not to assert against ISO/IEC and users of the JPEG |
||
25 | * 2000 Standard (Users) any of their rights under the copyright, not |
||
26 | * including other intellectual property rights, for this software module |
||
27 | * with respect to the usage by ISO/IEC and Users of this software module |
||
28 | * or modifications thereof for use in hardware or software products |
||
29 | * claiming conformance to the JPEG 2000 Standard. Those intending to use |
||
30 | * this software module in hardware or software products are advised that |
||
31 | * their use may infringe existing patents. The original developers of |
||
32 | * this software module, JJ2000 Partners and ISO/IEC assume no liability |
||
33 | * for use of this software module or modifications thereof. No license |
||
34 | * or right to this software module is granted for non JPEG 2000 Standard |
||
35 | * conforming products. JJ2000 Partners have full right to use this |
||
36 | * software module for his/her own purpose, assign or donate this |
||
37 | * software module to any third party and to inhibit third parties from |
||
38 | * using this software module for non JPEG 2000 Standard conforming |
||
39 | * products. This copyright notice must be included in all copies or |
||
40 | * derivative works of this software module. |
||
41 | * |
||
42 | * Copyright (c) 1999/2000 JJ2000 Partners. |
||
43 | * */ |
||
44 | using System; |
||
45 | using CSJ2K.j2k.quantization.quantizer; |
||
46 | using CSJ2K.j2k.codestream.writer; |
||
47 | using CSJ2K.j2k.wavelet.analysis; |
||
48 | using CSJ2K.j2k.quantization; |
||
49 | using CSJ2K.j2k.image.input; |
||
50 | using CSJ2K.j2k.wavelet; |
||
51 | using CSJ2K.j2k.encoder; |
||
52 | using CSJ2K.j2k.image; |
||
53 | using CSJ2K.j2k.util; |
||
54 | using CSJ2K.j2k.roi; |
||
55 | using CSJ2K.j2k; |
||
56 | namespace CSJ2K.j2k.roi.encoder |
||
57 | { |
||
58 | |||
59 | /// <summary> This class deals with the ROI functionality. |
||
60 | /// |
||
61 | /// <p>The ROI method is the Maxshift method. The ROIScaler works by scaling |
||
62 | /// the quantized wavelet coefficients that do not affect the ROI (i.e |
||
63 | /// background coefficients) so that these samples get a lower significance |
||
64 | /// than the ROI ones. By scaling the coefficients sufficiently, the ROI |
||
65 | /// coefficients can be recognized by their amplitude alone and no ROI mask |
||
66 | /// needs to be generated at the decoder side. |
||
67 | /// |
||
68 | /// <p>The source module must be a quantizer and code-block's data is exchange |
||
69 | /// with thanks to CBlkWTData instances. |
||
70 | /// |
||
71 | /// </summary> |
||
72 | /// <seealso cref="Quantizer"> |
||
73 | /// </seealso> |
||
74 | /// <seealso cref="CBlkWTData"> |
||
75 | /// |
||
76 | /// </seealso> |
||
77 | public class ROIScaler:ImgDataAdapter, CBlkQuantDataSrcEnc |
||
78 | { |
||
79 | /// <summary> Returns the horizontal offset of the code-block partition. Allowable |
||
80 | /// values are 0 and 1, nothing else. |
||
81 | /// |
||
82 | /// </summary> |
||
83 | virtual public int CbULX |
||
84 | { |
||
85 | get |
||
86 | { |
||
87 | return src.CbULX; |
||
88 | } |
||
89 | |||
90 | } |
||
91 | /// <summary> Returns the vertical offset of the code-block partition. Allowable |
||
92 | /// values are 0 and 1, nothing else. |
||
93 | /// |
||
94 | /// </summary> |
||
95 | virtual public int CbULY |
||
96 | { |
||
97 | get |
||
98 | { |
||
99 | return src.CbULY; |
||
100 | } |
||
101 | |||
102 | } |
||
103 | /// <summary> This function returns the ROI mask generator. |
||
104 | /// |
||
105 | /// </summary> |
||
106 | /// <returns> The roi mask generator |
||
107 | /// </returns> |
||
108 | virtual public ROIMaskGenerator ROIMaskGenerator |
||
109 | { |
||
110 | get |
||
111 | { |
||
112 | return mg; |
||
113 | } |
||
114 | |||
115 | } |
||
116 | /// <summary> This function returns the blockAligned flag |
||
117 | /// |
||
118 | /// </summary> |
||
119 | /// <returns> Flag indicating whether the ROIs were block aligned |
||
120 | /// </returns> |
||
121 | virtual public bool BlockAligned |
||
122 | { |
||
123 | get |
||
124 | { |
||
125 | return blockAligned; |
||
126 | } |
||
127 | |||
128 | } |
||
129 | /// <summary> Returns the parameters that are used in this class and |
||
130 | /// implementing classes. It returns a 2D String array. Each of the |
||
131 | /// 1D arrays is for a different option, and they have 3 |
||
132 | /// elements. The first element is the option name, the second one |
||
133 | /// is the synopsis, the third one is a long description of what |
||
134 | /// the parameter is and the fourth is its default value. The |
||
135 | /// synopsis or description may be 'null', in which case it is |
||
136 | /// assumed that there is no synopsis or description of the option, |
||
137 | /// respectively. Null may be returned if no options are supported. |
||
138 | /// |
||
139 | /// </summary> |
||
140 | /// <returns> the options name, their synopsis and their explanation, |
||
141 | /// or null if no options are supported. |
||
142 | /// |
||
143 | /// </returns> |
||
144 | public static System.String[][] ParameterInfo |
||
145 | { |
||
146 | get |
||
147 | { |
||
148 | return pinfo; |
||
149 | } |
||
150 | |||
151 | } |
||
152 | |||
153 | /// <summary>The prefix for ROI Scaler options: 'R' </summary> |
||
154 | public const char OPT_PREFIX = 'R'; |
||
155 | |||
156 | /// <summary>The list of parameters that are accepted for ROI coding. Options |
||
157 | /// for ROI Scaler start with 'R'. |
||
158 | /// </summary> |
||
159 | //UPGRADE_NOTE: Final was removed from the declaration of 'pinfo'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" |
||
160 | private static readonly System.String[][] pinfo = new System.String[][]{new System.String[]{"Rroi", "[<component idx>] R <left> <top> <width> <height>" + " or [<component idx>] C <centre column> <centre row> " + "<radius> or [<component idx>] A <filename>", "Specifies ROIs shape and location. The shape can be either " + "rectangular 'R', or circular 'C' or arbitrary 'A'. " + "Each new occurrence of an 'R', a 'C' or an 'A' is a new ROI. " + "For circular and rectangular ROIs, all values are " + "given as their pixel values relative to the canvas origin. " + "Arbitrary shapes must be included in a PGM file where non 0 " + "values correspond to ROI coefficients. The PGM file must have " + "the size as the image. " + "The component idx specifies which components " + "contain the ROI. The component index is specified as described " + "by points 3 and 4 in the general comment on tile-component idx. " + "If this option is used, the codestream is layer progressive by " + "default unless it is overridden by the 'Aptype' option.", null}, new System.String[]{"Ralign", "[on|off]", "By specifying this argument, the ROI mask will be " + "limited to covering only entire code-blocks. The ROI coding can " + "then be performed without any actual scaling of the coefficients " + "but by instead scaling the distortion estimates.", "off"}, new System.String[]{"Rstart_level", "<level>", "This argument forces the lowest <level> resolution levels to " + "belong to the ROI. By doing this, it is possible to avoid only " + "getting information for the ROI at an early stage of " + "transmission.<level> = 0 means the lowest resolution level " + "belongs to the ROI, 1 means the two lowest etc. (-1 deactivates" + " the option)", "-1"}, new System.String[]{"Rno_rect", "[on|off]", "This argument makes sure that the ROI mask generation is not done " + "using the fast ROI mask generation for rectangular ROIs " + "regardless of whether the specified ROIs are rectangular or not", "off"}}; |
||
161 | |||
162 | /// <summary>The maximum number of magnitude bit-planes in any subband. One value |
||
163 | /// for each tile-component |
||
164 | /// </summary> |
||
165 | private int[][] maxMagBits; |
||
166 | |||
167 | /// <summary>Flag indicating the presence of ROIs </summary> |
||
168 | private bool roi; |
||
169 | |||
170 | /// <summary>Flag indicating if block aligned ROIs are used </summary> |
||
171 | private bool blockAligned; |
||
172 | |||
173 | /// <summary>Number of resolution levels to include in ROI mask </summary> |
||
174 | private int useStartLevel; |
||
175 | |||
176 | /// <summary>The class generating the ROI mask </summary> |
||
177 | private ROIMaskGenerator mg; |
||
178 | |||
179 | /// <summary>The ROI mask </summary> |
||
180 | private DataBlkInt roiMask; |
||
181 | |||
182 | /// <summary>The source of quantized wavelet transform coefficients </summary> |
||
183 | private Quantizer src; |
||
184 | |||
185 | /// <summary> Constructor of the ROI scaler, takes a Quantizer as source of data to |
||
186 | /// scale. |
||
187 | /// |
||
188 | /// </summary> |
||
189 | /// <param name="src">The quantizer that is the source of data. |
||
190 | /// |
||
191 | /// </param> |
||
192 | /// <param name="mg">The mask generator that will be used for all components |
||
193 | /// |
||
194 | /// </param> |
||
195 | /// <param name="roi">Flag indicating whether there are rois specified. |
||
196 | /// |
||
197 | /// </param> |
||
198 | /// <param name="sLev">The resolution levels that belong entirely to ROI |
||
199 | /// |
||
200 | /// </param> |
||
201 | /// <param name="uba">Flag indicating whether block aligning is used. |
||
202 | /// |
||
203 | /// </param> |
||
204 | /// <param name="encSpec">The encoder specifications for addition of roi specs |
||
205 | /// |
||
206 | /// </param> |
||
207 | public ROIScaler(Quantizer src, ROIMaskGenerator mg, bool roi, int sLev, bool uba, EncoderSpecs encSpec):base(src) |
||
208 | { |
||
209 | this.src = src; |
||
210 | this.roi = roi; |
||
211 | this.useStartLevel = sLev; |
||
212 | if (roi) |
||
213 | { |
||
214 | // If there is no ROI, no need to do this |
||
215 | this.mg = mg; |
||
216 | roiMask = new DataBlkInt(); |
||
217 | calcMaxMagBits(encSpec); |
||
218 | blockAligned = uba; |
||
219 | } |
||
220 | } |
||
221 | |||
222 | /// <summary> Since ROI scaling is always a reversible operation, it calls |
||
223 | /// isReversible() method of it source (the quantizer module). |
||
224 | /// |
||
225 | /// </summary> |
||
226 | /// <param name="t">The tile to test for reversibility |
||
227 | /// |
||
228 | /// </param> |
||
229 | /// <param name="c">The component to test for reversibility |
||
230 | /// |
||
231 | /// </param> |
||
232 | /// <returns> True if the quantized data is reversible, false if not. |
||
233 | /// |
||
234 | /// </returns> |
||
235 | public virtual bool isReversible(int t, int c) |
||
236 | { |
||
237 | return src.isReversible(t, c); |
||
238 | } |
||
239 | |||
240 | /// <summary> Returns a reference to the subband tree structure representing the |
||
241 | /// subband decomposition for the specified tile-component. |
||
242 | /// |
||
243 | /// </summary> |
||
244 | /// <param name="t">The index of the tile. |
||
245 | /// |
||
246 | /// </param> |
||
247 | /// <param name="c">The index of the component. |
||
248 | /// |
||
249 | /// </param> |
||
250 | /// <returns> The subband tree structure, see SubbandAn. |
||
251 | /// |
||
252 | /// </returns> |
||
253 | /// <seealso cref="SubbandAn"> |
||
254 | /// |
||
255 | /// </seealso> |
||
256 | /// <seealso cref="Subband"> |
||
257 | /// |
||
258 | /// </seealso> |
||
259 | public virtual SubbandAn getAnSubbandTree(int t, int c) |
||
260 | { |
||
261 | return src.getAnSubbandTree(t, c); |
||
262 | } |
||
263 | |||
264 | /// <summary> Creates a ROIScaler object. The Quantizer is the source of data to |
||
265 | /// scale. |
||
266 | /// |
||
267 | /// <p>The ROI Scaler creates a ROIMaskGenerator depending on what ROI |
||
268 | /// information is in the ParameterList. If only rectangular ROI are used, |
||
269 | /// the fast mask generator for rectangular ROI can be used.</p> |
||
270 | /// |
||
271 | /// </summary> |
||
272 | /// <param name="src">The source of data to scale |
||
273 | /// |
||
274 | /// </param> |
||
275 | /// <param name="pl">The parameter list (or options). |
||
276 | /// |
||
277 | /// </param> |
||
278 | /// <param name="encSpec">The encoder specifications for addition of roi specs |
||
279 | /// |
||
280 | /// </param> |
||
281 | /// <exception cref="IllegalArgumentException">If an error occurs while parsing |
||
282 | /// the options in 'pl' |
||
283 | /// |
||
284 | /// </exception> |
||
285 | public static ROIScaler createInstance(Quantizer src, ParameterList pl, EncoderSpecs encSpec) |
||
286 | { |
||
287 | System.Collections.ArrayList roiVector = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); |
||
288 | ROIMaskGenerator maskGen = null; |
||
289 | |||
290 | // Check parameters |
||
291 | pl.checkList(OPT_PREFIX, CSJ2K.j2k.util.ParameterList.toNameArray(pinfo)); |
||
292 | |||
293 | // Get parameters and check if there are and ROIs specified |
||
294 | System.String roiopt = pl.getParameter("Rroi"); |
||
295 | if (roiopt == null) |
||
296 | { |
||
297 | // No ROIs specified! Create ROIScaler with no mask generator |
||
298 | return new ROIScaler(src, null, false, - 1, false, encSpec); |
||
299 | } |
||
300 | |||
301 | // Check if the lowest resolution levels should belong to the ROI |
||
302 | int sLev = pl.getIntParameter("Rstart_level"); |
||
303 | |||
304 | // Check if the ROIs are block-aligned |
||
305 | bool useBlockAligned = pl.getBooleanParameter("Ralign"); |
||
306 | |||
307 | // Check if generic mask generation is specified |
||
308 | bool onlyRect = !pl.getBooleanParameter("Rno_rect"); |
||
309 | |||
310 | // Parse the ROIs |
||
311 | parseROIs(roiopt, src.NumComps, roiVector); |
||
312 | ROI[] roiArray = new ROI[roiVector.Count]; |
||
313 | roiVector.CopyTo(roiArray); |
||
314 | |||
315 | // If onlyRect has been forced, check if there are any non-rectangular |
||
316 | // ROIs specified. Currently, only the presence of circular ROIs will |
||
317 | // make this false |
||
318 | if (onlyRect) |
||
319 | { |
||
320 | for (int i = roiArray.Length - 1; i >= 0; i--) |
||
321 | if (!roiArray[i].rect) |
||
322 | { |
||
323 | onlyRect = false; |
||
324 | break; |
||
325 | } |
||
326 | } |
||
327 | |||
328 | if (onlyRect) |
||
329 | { |
||
330 | // It's possible to use the fast ROI mask generation when only |
||
331 | // rectangular ROIs are specified. |
||
332 | maskGen = new RectROIMaskGenerator(roiArray, src.NumComps); |
||
333 | } |
||
334 | else |
||
335 | { |
||
336 | // It's necessary to use the generic mask generation |
||
337 | maskGen = new ArbROIMaskGenerator(roiArray, src.NumComps, src); |
||
338 | } |
||
339 | return new ROIScaler(src, maskGen, true, sLev, useBlockAligned, encSpec); |
||
340 | } |
||
341 | |||
342 | /// <summary> This function parses the values given for the ROIs with the argument |
||
343 | /// -Rroi. Currently only circular and rectangular ROIs are supported. |
||
344 | /// |
||
345 | /// <p>A rectangular ROI is indicated by a 'R' followed the coordinates for |
||
346 | /// the upper left corner of the ROI and then its width and height.</p> |
||
347 | /// |
||
348 | /// <p>A circular ROI is indicated by a 'C' followed by the coordinates of |
||
349 | /// the circle center and then the radius.</p> |
||
350 | /// |
||
351 | /// <p>Before the R and C values, the component that are affected by the |
||
352 | /// ROI are indicated.</p> |
||
353 | /// |
||
354 | /// </summary> |
||
355 | /// <param name="roiopt">The info on the ROIs |
||
356 | /// |
||
357 | /// </param> |
||
358 | /// <param name="nc">number of components |
||
359 | /// |
||
360 | /// </param> |
||
361 | /// <param name="roiVector">The vcector containing the ROI parsed from the cmd line |
||
362 | /// |
||
363 | /// </param> |
||
364 | /// <returns> The ROIs specified in roiopt |
||
365 | /// |
||
366 | /// </returns> |
||
367 | protected internal static System.Collections.ArrayList parseROIs(System.String roiopt, int nc, System.Collections.ArrayList roiVector) |
||
368 | { |
||
369 | //ROI[] ROIs; |
||
370 | ROI roi; |
||
371 | SupportClass.Tokenizer stok; |
||
372 | //char tok; |
||
373 | int nrOfROIs = 0; |
||
374 | //char c; |
||
375 | int ulx, uly, w, h, x, y, rad; // comp removed |
||
376 | bool[] roiInComp = null; |
||
377 | |||
378 | stok = new SupportClass.Tokenizer(roiopt); |
||
379 | |||
380 | System.String word; |
||
381 | while (stok.HasMoreTokens()) |
||
382 | { |
||
383 | word = stok.NextToken(); |
||
384 | |||
385 | switch (word[0]) |
||
386 | { |
||
387 | |||
388 | case 'c': // Components specification |
||
389 | roiInComp = ModuleSpec.parseIdx(word, nc); |
||
390 | break; |
||
391 | |||
392 | case 'R': // Rectangular ROI to be read |
||
393 | nrOfROIs++; |
||
394 | try |
||
395 | { |
||
396 | word = stok.NextToken(); |
||
397 | ulx = (System.Int32.Parse(word)); |
||
398 | word = stok.NextToken(); |
||
399 | uly = (System.Int32.Parse(word)); |
||
400 | word = stok.NextToken(); |
||
401 | w = (System.Int32.Parse(word)); |
||
402 | word = stok.NextToken(); |
||
403 | h = (System.Int32.Parse(word)); |
||
404 | } |
||
405 | catch (System.FormatException) |
||
406 | { |
||
407 | throw new System.ArgumentException("Bad parameter for " + "'-Rroi R' option : " + word); |
||
408 | } |
||
409 | catch (System.ArgumentOutOfRangeException) |
||
410 | { |
||
411 | throw new System.ArgumentException("Wrong number of " + "parameters for " + "h'-Rroi R' option."); |
||
412 | } |
||
413 | |||
414 | // If the ROI is component-specific, check which comps. |
||
415 | if (roiInComp != null) |
||
416 | for (int i = 0; i < nc; i++) |
||
417 | { |
||
418 | if (roiInComp[i]) |
||
419 | { |
||
420 | roi = new ROI(i, ulx, uly, w, h); |
||
421 | roiVector.Add(roi); |
||
422 | } |
||
423 | } |
||
424 | else |
||
425 | { |
||
426 | // Otherwise add ROI for all components |
||
427 | for (int i = 0; i < nc; i++) |
||
428 | { |
||
429 | roi = new ROI(i, ulx, uly, w, h); |
||
430 | roiVector.Add(roi); |
||
431 | } |
||
432 | } |
||
433 | break; |
||
434 | |||
435 | case 'C': // Circular ROI to be read |
||
436 | nrOfROIs++; |
||
437 | |||
438 | try |
||
439 | { |
||
440 | word = stok.NextToken(); |
||
441 | x = (System.Int32.Parse(word)); |
||
442 | word = stok.NextToken(); |
||
443 | y = (System.Int32.Parse(word)); |
||
444 | word = stok.NextToken(); |
||
445 | rad = (System.Int32.Parse(word)); |
||
446 | } |
||
447 | catch (System.FormatException) |
||
448 | { |
||
449 | throw new System.ArgumentException("Bad parameter for " + "'-Rroi C' option : " + word); |
||
450 | } |
||
451 | catch (System.ArgumentOutOfRangeException) |
||
452 | { |
||
453 | throw new System.ArgumentException("Wrong number of " + "parameters for " + "'-Rroi C' option."); |
||
454 | } |
||
455 | |||
456 | // If the ROI is component-specific, check which comps. |
||
457 | if (roiInComp != null) |
||
458 | for (int i = 0; i < nc; i++) |
||
459 | { |
||
460 | if (roiInComp[i]) |
||
461 | { |
||
462 | roi = new ROI(i, x, y, rad); |
||
463 | roiVector.Add(roi); |
||
464 | } |
||
465 | } |
||
466 | else |
||
467 | { |
||
468 | // Otherwise add ROI for all components |
||
469 | for (int i = 0; i < nc; i++) |
||
470 | { |
||
471 | roi = new ROI(i, x, y, rad); |
||
472 | roiVector.Add(roi); |
||
473 | } |
||
474 | } |
||
475 | break; |
||
476 | |||
477 | case 'A': // ROI wth arbitrary shape |
||
478 | nrOfROIs++; |
||
479 | |||
480 | System.String filename; |
||
481 | ImgReaderPGM maskPGM = null; |
||
482 | |||
483 | try |
||
484 | { |
||
485 | filename = stok.NextToken(); |
||
486 | } |
||
487 | catch (System.ArgumentOutOfRangeException) |
||
488 | { |
||
489 | throw new System.ArgumentException("Wrong number of " + "parameters for " + "'-Rroi A' option."); |
||
490 | } |
||
491 | try |
||
492 | { |
||
493 | maskPGM = new ImgReaderPGM(filename); |
||
494 | } |
||
495 | catch (System.IO.IOException) |
||
496 | { |
||
497 | throw new System.ApplicationException("Cannot read PGM file with ROI"); |
||
498 | } |
||
499 | |||
500 | // If the ROI is component-specific, check which comps. |
||
501 | if (roiInComp != null) |
||
502 | for (int i = 0; i < nc; i++) |
||
503 | { |
||
504 | if (roiInComp[i]) |
||
505 | { |
||
506 | roi = new ROI(i, maskPGM); |
||
507 | roiVector.Add(roi); |
||
508 | } |
||
509 | } |
||
510 | else |
||
511 | { |
||
512 | // Otherwise add ROI for all components |
||
513 | for (int i = 0; i < nc; i++) |
||
514 | { |
||
515 | roi = new ROI(i, maskPGM); |
||
516 | roiVector.Add(roi); |
||
517 | } |
||
518 | } |
||
519 | break; |
||
520 | |||
521 | default: |
||
522 | throw new System.ApplicationException("Bad parameters for ROI nr " + roiVector.Count); |
||
523 | |||
524 | } |
||
525 | } |
||
526 | |||
527 | return roiVector; |
||
528 | } |
||
529 | |||
530 | /// <summary> This function gets a datablk from the entropy coder. The sample sin the |
||
531 | /// block, which consists of the quantized coefficients from the quantizer, |
||
532 | /// are scaled by the values given for any ROIs specified. |
||
533 | /// |
||
534 | /// <p>The function calls on a ROIMaskGenerator to get the mask for scaling |
||
535 | /// the coefficients in the current block.</p> |
||
536 | /// |
||
537 | /// <p>The data returned by this method is a copy of the orignal |
||
538 | /// data. Therfore it can be modified "in place" without any problems after |
||
539 | /// being returned. The 'offset' of the returned data is 0, and the 'scanw' |
||
540 | /// is the same as the code-block width. See the 'CBlkWTData' class.</p> |
||
541 | /// |
||
542 | /// </summary> |
||
543 | /// <param name="c">The component for which to return the next code-block. |
||
544 | /// |
||
545 | /// </param> |
||
546 | /// <param name="cblk">If non-null this object will be used to return the new |
||
547 | /// code-block. If null a new one will be allocated and returned. If the |
||
548 | /// "data" array of the object is non-null it will be reused, if possible, |
||
549 | /// to return the data. |
||
550 | /// |
||
551 | /// </param> |
||
552 | /// <returns> The next code-block in the current tile for component 'n', or |
||
553 | /// null if all code-blocks for the current tile have been returned. |
||
554 | /// |
||
555 | /// </returns> |
||
556 | /// <seealso cref="CBlkWTData"> |
||
557 | /// |
||
558 | /// </seealso> |
||
559 | public virtual CBlkWTData getNextCodeBlock(int c, CBlkWTData cblk) |
||
560 | { |
||
561 | return getNextInternCodeBlock(c, cblk); |
||
562 | } |
||
563 | |||
564 | /// <summary> This function gets a datablk from the entropy coder. The sample sin the |
||
565 | /// block, which consists of the quantized coefficients from the quantizer, |
||
566 | /// are scaled by the values given for any ROIs specified. |
||
567 | /// |
||
568 | /// <p>The function calls on a ROIMaskGenerator to get the mask for scaling |
||
569 | /// the coefficients in the current block.</p> |
||
570 | /// |
||
571 | /// </summary> |
||
572 | /// <param name="c">The component for which to return the next code-block. |
||
573 | /// |
||
574 | /// </param> |
||
575 | /// <param name="cblk">If non-null this object will be used to return the new |
||
576 | /// code-block. If null a new one will be allocated and returned. If the |
||
577 | /// "data" array of the object is non-null it will be reused, if possible, |
||
578 | /// to return the data. |
||
579 | /// |
||
580 | /// </param> |
||
581 | /// <returns> The next code-block in the current tile for component 'n', or |
||
582 | /// null if all code-blocks for the current tile have been returned. |
||
583 | /// |
||
584 | /// </returns> |
||
585 | /// <seealso cref="CBlkWTData"> |
||
586 | /// |
||
587 | /// </seealso> |
||
588 | public virtual CBlkWTData getNextInternCodeBlock(int c, CBlkWTData cblk) |
||
589 | { |
||
590 | int mi, i, j, k, wrap; |
||
591 | int ulx, uly, w, h; |
||
592 | DataBlkInt mask = roiMask; // local copy of mask |
||
593 | int[] maskData; // local copy of mask data |
||
594 | int[] data; // local copy of quantized data |
||
595 | int tmp; |
||
596 | int bitMask = 0x7FFFFFFF; |
||
597 | SubbandAn root, sb; |
||
598 | int maxBits = 0; // local copy |
||
599 | bool roiInTile; |
||
600 | bool sbInMask; |
||
601 | int nROIcoeff = 0; |
||
602 | |||
603 | // Get codeblock's data from quantizer |
||
604 | cblk = src.getNextCodeBlock(c, cblk); |
||
605 | |||
606 | // If there is no ROI in the image, or if we already got all |
||
607 | // code-blocks |
||
608 | if (!roi || cblk == null) |
||
609 | { |
||
610 | return cblk; |
||
611 | } |
||
612 | |||
613 | data = (int[]) cblk.Data; |
||
614 | sb = cblk.sb; |
||
615 | ulx = cblk.ulx; |
||
616 | uly = cblk.uly; |
||
617 | w = cblk.w; |
||
618 | h = cblk.h; |
||
619 | sbInMask = (sb.resLvl <= useStartLevel); |
||
620 | |||
621 | // Check that there is an array for the mask and set it to zero |
||
622 | maskData = mask.DataInt; // local copy of mask data |
||
623 | if (maskData == null || w * h > maskData.Length) |
||
624 | { |
||
625 | maskData = new int[w * h]; |
||
626 | mask.DataInt = maskData; |
||
627 | } |
||
628 | else |
||
629 | { |
||
630 | for (i = w * h - 1; i >= 0; i--) |
||
631 | maskData[i] = 0; |
||
632 | } |
||
633 | mask.ulx = ulx; |
||
634 | mask.uly = uly; |
||
635 | mask.w = w; |
||
636 | mask.h = h; |
||
637 | |||
638 | // Get ROI mask from generator |
||
639 | root = src.getAnSubbandTree(tIdx, c); |
||
640 | maxBits = maxMagBits[tIdx][c]; |
||
641 | roiInTile = mg.getROIMask(mask, root, maxBits, c); |
||
642 | |||
643 | // If there is no ROI in this tile, return the code-block untouched |
||
644 | if (!roiInTile && (!sbInMask)) |
||
645 | { |
||
646 | cblk.nROIbp = 0; |
||
647 | return cblk; |
||
648 | } |
||
649 | |||
650 | // Update field containing the number of ROI magnitude bit-planes |
||
651 | cblk.nROIbp = cblk.magbits; |
||
652 | |||
653 | // If the entire subband belongs to the ROI mask, The code-block is |
||
654 | // set to belong entirely to the ROI with the highest scaling value |
||
655 | if (sbInMask) |
||
656 | { |
||
657 | // Scale the wmse so that instead of scaling the coefficients, the |
||
658 | // wmse is scaled. |
||
659 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
660 | cblk.wmseScaling *= (float) (1 << (maxBits << 1)); |
||
661 | cblk.nROIcoeff = w * h; |
||
662 | return cblk; |
||
663 | } |
||
664 | |||
665 | // In 'block aligned' mode, the code-block is set to belong entirely |
||
666 | // to the ROI with the highest scaling value if one coefficient, at |
||
667 | // least, belongs to the ROI |
||
668 | if (blockAligned) |
||
669 | { |
||
670 | wrap = cblk.scanw - w; |
||
671 | mi = h * w - 1; |
||
672 | i = cblk.offset + cblk.scanw * (h - 1) + w - 1; |
||
673 | int nroicoeff = 0; |
||
674 | for (j = h; j > 0; j--) |
||
675 | { |
||
676 | for (k = w - 1; k >= 0; k--, i--, mi--) |
||
677 | { |
||
678 | if (maskData[mi] != 0) |
||
679 | { |
||
680 | nroicoeff++; |
||
681 | } |
||
682 | } |
||
683 | i -= wrap; |
||
684 | } |
||
685 | if (nroicoeff != 0) |
||
686 | { |
||
687 | // Include the subband |
||
688 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
689 | cblk.wmseScaling *= (float) (1 << (maxBits << 1)); |
||
690 | cblk.nROIcoeff = w * h; |
||
691 | } |
||
692 | return cblk; |
||
693 | } |
||
694 | |||
695 | // Scale background coefficients |
||
696 | bitMask = (((1 << cblk.magbits) - 1) << (31 - cblk.magbits)); |
||
697 | wrap = cblk.scanw - w; |
||
698 | mi = h * w - 1; |
||
699 | i = cblk.offset + cblk.scanw * (h - 1) + w - 1; |
||
700 | for (j = h; j > 0; j--) |
||
701 | { |
||
702 | for (k = w; k > 0; k--, i--, mi--) |
||
703 | { |
||
704 | tmp = data[i]; |
||
705 | if (maskData[mi] != 0) |
||
706 | { |
||
707 | // ROI coeff. We need to erase fractional bits to ensure |
||
708 | // that they do not conflict with BG coeffs. This is only |
||
709 | // strictly necessary for ROI coeffs. which non-fractional |
||
710 | // magnitude is zero, but much better BG quality can be |
||
711 | // achieved if done if reset to zero since coding zeros is |
||
712 | // much more efficient (the entropy coder knows nothing |
||
713 | // about ROI and cannot avoid coding the ROI fractional |
||
714 | // bits, otherwise this would not be necessary). |
||
715 | data[i] = (unchecked((int) 0x80000000) & tmp) | (tmp & bitMask); |
||
716 | nROIcoeff++; |
||
717 | } |
||
718 | else |
||
719 | { |
||
720 | // BG coeff. it is not necessary to erase fractional bits |
||
721 | data[i] = (unchecked((int) 0x80000000) & tmp) | ((tmp & 0x7FFFFFFF) >> maxBits); |
||
722 | } |
||
723 | } |
||
724 | i -= wrap; |
||
725 | } |
||
726 | |||
727 | // Modify the number of significant bit-planes in the code-block |
||
728 | cblk.magbits += maxBits; |
||
729 | |||
730 | // Store the number of ROI coefficients present in the code-block |
||
731 | cblk.nROIcoeff = nROIcoeff; |
||
732 | |||
733 | return cblk; |
||
734 | } |
||
735 | |||
736 | /// <summary> This function returns the flag indicating if any ROI functionality used |
||
737 | /// |
||
738 | /// </summary> |
||
739 | /// <returns> Flag indicating whether there are ROIs in the image |
||
740 | /// </returns> |
||
741 | public virtual bool useRoi() |
||
742 | { |
||
743 | return roi; |
||
744 | } |
||
745 | |||
746 | /// <summary> Changes the current tile, given the new indexes. An |
||
747 | /// IllegalArgumentException is thrown if the indexes do not |
||
748 | /// correspond to a valid tile. |
||
749 | /// |
||
750 | /// </summary> |
||
751 | /// <param name="x">The horizontal index of the tile. |
||
752 | /// |
||
753 | /// </param> |
||
754 | /// <param name="y">The vertical index of the new tile. |
||
755 | /// |
||
756 | /// </param> |
||
757 | public override void setTile(int x, int y) |
||
758 | { |
||
759 | base.setTile(x, y); |
||
760 | if (roi) |
||
761 | mg.tileChanged(); |
||
762 | } |
||
763 | |||
764 | /// <summary> Advances to the next tile, in standard scan-line order (by rows then |
||
765 | /// columns). An NoNextElementException is thrown if the current tile is |
||
766 | /// the last one (i.e. there is no next tile). |
||
767 | /// |
||
768 | /// </summary> |
||
769 | public override void nextTile() |
||
770 | { |
||
771 | base.nextTile(); |
||
772 | if (roi) |
||
773 | mg.tileChanged(); |
||
774 | } |
||
775 | |||
776 | /// <summary> Calculates the maximum amount of magnitude bits for each |
||
777 | /// tile-component, and stores it in the 'maxMagBits' array. This is called |
||
778 | /// by the constructor |
||
779 | /// |
||
780 | /// </summary> |
||
781 | /// <param name="encSpec">The encoder specifications for addition of roi specs |
||
782 | /// |
||
783 | /// </param> |
||
784 | private void calcMaxMagBits(EncoderSpecs encSpec) |
||
785 | { |
||
786 | int tmp; |
||
787 | MaxShiftSpec rois = encSpec.rois; |
||
788 | |||
789 | int nt = src.getNumTiles(); |
||
790 | int nc = src.NumComps; |
||
791 | |||
792 | maxMagBits = new int[nt][]; |
||
793 | for (int i = 0; i < nt; i++) |
||
794 | { |
||
795 | maxMagBits[i] = new int[nc]; |
||
796 | } |
||
797 | |||
798 | src.setTile(0, 0); |
||
799 | for (int t = 0; t < nt; t++) |
||
800 | { |
||
801 | for (int c = nc - 1; c >= 0; c--) |
||
802 | { |
||
803 | tmp = src.getMaxMagBits(c); |
||
804 | maxMagBits[t][c] = tmp; |
||
805 | rois.setTileCompVal(t, c, (System.Object) tmp); |
||
806 | } |
||
807 | if (t < nt - 1) |
||
808 | src.nextTile(); |
||
809 | } |
||
810 | // Reset to current initial tile position |
||
811 | src.setTile(0, 0); |
||
812 | } |
||
813 | } |
||
814 | } |