<html><head><meta http-equiv="Content-Type" content="text/html charset=windows-1252"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">Hi,<div><br></div><div>ok, sorry for the lurid subject line - it's not that bad, but I think the "incorrect" part is kind of important.</div><div><br></div><div><br></div><div>First regarding the slow (feel free to skip to this paragraph...). I played with unsigned short to ARGB conversion and noticed that it divides by scale factor for every pixel.</div><div>I thought that maybe we could speed it up a little by replacing that with a multiplication. Amazingly even in a language as Java that is seemingly far removed from the CPU this actually matters.</div><div>I have pushed a RealARGBConverterBenchmark which uses cursors and a converter to convert a UnsignedByteType image to ARGBType, <a href="https://github.com/imagej/imglib/commit/fbdf633a8b6d1c2894f9ef08eb3a642c010ca44e">https://github.com/imagej/imglib/commit/fbdf633a8b6d1c2894f9ef08eb3a642c010ca44e</a></div><div>Replacing the division to multiplication (and some minor tweaks) made the benchmark go from 28ms to 12ms, <a href="https://github.com/imagej/imglib/commit/5c6f40f0492bee2159eebe1ffb1e5b5f1bcc6a8d">https://github.com/imagej/imglib/commit/5c6f40f0492bee2159eebe1ffb1e5b5f1bcc6a8d</a>. Amazing.</div><div>Then I wanted to do that for all of the converters, got side-tracked, and as usual the 10-minute thing turned into 2 hours obsessing with details: is the converter math actually correct?</div><div><br></div><div><br></div><div>I think the linear range conversion in the Real*Converters is wrong.</div><div>Mathematically, it is obviously simple. We have to intervals [minA, maxA] and [minB, maxB] and want to convert (linearly) xA to xB:</div><div>xB = minA + (xA - minA) / (maxA-minA) * (maxB-minB)</div><div>Thats exactly whats implemented in, for example, RealUnsignedByteConverter.</div><div>Where it gets tricky is quantisation.</div><div><br></div><div><div>In RealUnsignedByteConverter:</div><div><span style="font-family: Monaco; font-size: 11px; ">output.set( Math.min( 255, roundPositive( Math.max( 0, ( ( a - </span><span style="font-family: Monaco; font-size: 11px; color: rgb(3, 38, 204); ">min</span><span style="font-family: Monaco; font-size: 11px; "> ) / </span><span style="font-family: Monaco; font-size: 11px; color: rgb(3, 38, 204); ">scale</span><span style="font-family: Monaco; font-size: 11px; "> * 255.0 ) ) ) ) );</span></div></div><div><div>Stripping the bounds check:</div><div><span style="font-family: Monaco; font-size: 11px; ">output.set( roundPositive( ( a - </span><span style="font-family: Monaco; font-size: 11px; color: rgb(3, 38, 204); ">min</span><span style="font-family: Monaco; font-size: 11px; "> ) / </span><span style="font-family: Monaco; font-size: 11px; color: rgb(3, 38, 204); ">scale</span><span style="font-family: Monaco; font-size: 11px; "> * 255.0 ) );</span></div></div><div><div>where <span style="font-family: Monaco; font-size: 11px; ">roundPositive</span> is just normal rounding, and <span style="color: rgb(3, 38, 204); font-family: Monaco; font-size: 11px; ">scale</span> = (maxA-minA) as above and <span style="font-family: Monaco; font-size: 11px; ">255.0 = (maxB-minB).</span></div></div><div><div>I think, the <span style="font-family: Monaco; font-size: 11px; ">roundPositive</span> is supposed to take care of quantisation.</div></div><div><br></div><div>Now let's look a simplified example where we want to convert a 4-bit value into a 2-bit value.</div><div>Intuitively I would expect the converter to perform a uniform re-binning. There are 16 4-bit values that need to be distributed into 4 2-bit bins.</div><div>What should happen is that we keep the upper 2 bits of the 4-bit value, that is:</div><div>0000-0011 map to 00</div><div>…</div><div>1100-1111 map to 11</div><div>At least that is what my intuition tells me.</div><div>Now if you go through the motions with the current converter logic you'll find that 1100 actually is mapped to 10. Likewise, 0011 is mapped to 01. There are 2 bins with 3 values each and 2 bins with 5. Not uniform.</div><div><br></div><div>I think this is wrong and I would fix it, but first I wanted to ask whether I'm missing something here?</div><div>Especially, Stephan, maybe you can comment because you implemented current logic.</div><div><br></div><div><br></div><div>best regards,</div><div>Tobias</div></body></html>