0
$\begingroup$

Are there any other techniques I could use to improve the performance of the below timed operation that converts a "Byte" type Grayscale image to "Real32" using the given lookup table.

I've tried using ImageApply with a compiled function to perform the lookup, but that is actually a bit slower.

testImage = Image[RandomImage[1, {1600, 1600*4}, ColorSpace -> "Grayscale"], "Byte"];

decompandImage[img_?ImageQ] :=
  With[{lut = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 
   16, 17, 18, 19, 20, 21, 22, 23, 25, 27, 29, 31, 33, 35, 37, 39,
    41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 67, 71, 75, 
   79, 83, 87, 91, 95, 99, 103, 107, 111, 115, 119, 123, 127, 131,
    135, 139, 143, 147, 151, 155, 159, 163, 167, 171, 175, 179, 
   183, 187, 191, 195, 199, 203, 207, 211, 215, 219, 223, 227, 
   231, 235, 239, 243, 247, 255, 263, 271, 279, 287, 295, 303, 
   311, 319, 327, 335, 343, 351, 359, 367, 375, 383, 391, 399, 
   407, 415, 423, 431, 439, 447, 455, 463, 471, 479, 487, 495, 
   503, 511, 519, 527, 535, 543, 551, 559, 567, 575, 583, 591, 
   599, 607, 615, 623, 631, 639, 647, 655, 663, 671, 679, 687, 
   695, 703, 711, 719, 727, 735, 743, 751, 759, 767, 775, 783, 
   791, 799, 807, 815, 823, 831, 839, 847, 855, 863, 871, 879, 
   887, 895, 903, 911, 919, 927, 935, 943, 951, 959, 967, 975, 
   983, 991, 999, 1007, 1023, 1039, 1055, 1071, 1087, 1103, 1119, 
   1135, 1151, 1167, 1183, 1199, 1215, 1231, 1247, 1263, 1279, 
   1295, 1311, 1327, 1343, 1359, 1375, 1391, 1407, 1439, 1471, 
   1503, 1535, 1567, 1599, 1631, 1663, 1695, 1727, 1759, 1791, 
   1823, 1855, 1887, 1919, 1951, 1983, 2015, 2047, 2079, 2111, 
   2143, 2175, 2207, 2239, 2271, 2303, 2335, 2367, 2399, 2431, 
   2463, 2495, 2527, 2559, 2591, 2623, 2655, 2687, 2719, 2751, 
   2783, 2815, 2847, 2879}/2879. (* // N // Developer`ToPackedArray *)
  },
  Image[Map[lut[[# + 1]] &, ImageData[img, "Byte"], {2}], "Real32"]
  ];

AbsoluteTiming[test4 = decompandImage[testImage]] [[1]]
$\endgroup$
  • 1
    $\begingroup$ Remove {2} will make it bit faster i think, with same result. Also you should move + 1 so you have ImageData[img, "Byte"] + 1 $\endgroup$ – Coolwater Jul 17 '17 at 19:40
  • $\begingroup$ Thanks @Coolwater. Removing the '{2}' gave a significant improvement. Moving the +1 was produced either no change or a slight slow-down. $\endgroup$ – Brian Swift Jul 17 '17 at 22:44
  • $\begingroup$ Just changing the code after LUT definition to Image[Partition[lut[[Join @@ ImageData[img, "Byte"] + 1]], First@ImageDimensions@img], "Real32"]] should speed things nicely... $\endgroup$ – ciao Jul 18 '17 at 2:25
  • $\begingroup$ Thank for your input @ciao. Your suggestion runs .28s, slightly faster than my initial implementation, but significantly slower than Coolwater and Henrick's. $\endgroup$ – Brian Swift Jul 21 '17 at 4:17
1
$\begingroup$

Buildung on Coolwater's comment, one can obtain a slight improvement by compiling this into a Listable and parallelized CompiledFunction:

clookup = Compile[{{lut, _Real, 1}, {x, _Integer, 1}},
   lut[[x + 1]],
   CompilationTarget -> "C",
   RuntimeAttributes -> {Listable},
   Parallelization -> True
   ];

lut = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 
    18, 19, 20, 21, 22, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 
    45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 67, 71, 75, 79, 83, 87, 
    91, 95, 99, 103, 107, 111, 115, 119, 123, 127, 131, 135, 139, 143,
     147, 151, 155, 159, 163, 167, 171, 175, 179, 183, 187, 191, 195, 
    199, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239, 243, 247, 
    255, 263, 271, 279, 287, 295, 303, 311, 319, 327, 335, 343, 351, 
    359, 367, 375, 383, 391, 399, 407, 415, 423, 431, 439, 447, 455, 
    463, 471, 479, 487, 495, 503, 511, 519, 527, 535, 543, 551, 559, 
    567, 575, 583, 591, 599, 607, 615, 623, 631, 639, 647, 655, 663, 
    671, 679, 687, 695, 703, 711, 719, 727, 735, 743, 751, 759, 767, 
    775, 783, 791, 799, 807, 815, 823, 831, 839, 847, 855, 863, 871, 
    879, 887, 895, 903, 911, 919, 927, 935, 943, 951, 959, 967, 975, 
    983, 991, 999, 1007, 1023, 1039, 1055, 1071, 1087, 1103, 1119, 
    1135, 1151, 1167, 1183, 1199, 1215, 1231, 1247, 1263, 1279, 1295, 
    1311, 1327, 1343, 1359, 1375, 1391, 1407, 1439, 1471, 1503, 1535, 
    1567, 1599, 1631, 1663, 1695, 1727, 1759, 1791, 1823, 1855, 1887, 
    1919, 1951, 1983, 2015, 2047, 2079, 2111, 2143, 2175, 2207, 2239, 
    2271, 2303, 2335, 2367, 2399, 2431, 2463, 2495, 2527, 2559, 2591, 
    2623, 2655, 2687, 2719, 2751, 2783, 2815, 2847, 2879}/2879.;

cdecompandImage[img_?ImageQ] := Image[clookup[lut, ImageData[img, "Byte"]], "Real32"];
$\endgroup$
  • $\begingroup$ Thanks @Henrick, that compilation style also produced a significant improvement. My function -> .33s , Removing {2} -> .16s , compiled/listable -> .10s $\endgroup$ – Brian Swift Jul 17 '17 at 23:24
  • $\begingroup$ Image[ImageApply[lut[[#*255 + 1]] &, Image[testImage, "Bit16"]], "Real32"] - though serial - is very fast as well, however does not give exactly the same result as above, as 16bit requantisation is being done, but no grayscale level is being lost for the given lut. However Image[ImageApply[lut[[#*255 + 1]] &, testImage], "Real32"] would do 8bit requantisation, so many grayscale levels would get lost for this lut. Is there any particular reason why Real32 requested? Bit16 is sufficient in many practical cases, so the back casting could be skipped. $\endgroup$ – UDB Jul 28 '17 at 17:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.