/dev/Gems/ImageProcessing/Code/Source/Converters/ColorChart.cpp

https://github.com/aws/lumberyard · C++ · 315 lines · 230 code · 50 blank · 35 comment · 25 complexity · 7f12631c6346f7d632a60e07004cfa67 MD5 · raw file

  1. /*
  2. * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
  3. * its licensors.
  4. *
  5. * For complete copyright and license terms please see the LICENSE at the root of this
  6. * distribution (the "License"). All use of this software is governed by the License,
  7. * or, if provided, by the license below or the license accompanying this file. Do not
  8. * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
  9. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. *
  11. */
  12. #include <ImageProcessing_precompiled.h>
  13. #include <Processing/ImageObjectImpl.h>
  14. #include <Processing/ImageToProcess.h>
  15. namespace ImageProcessing
  16. {
  17. const int COLORCHART_IMAGE_WIDTH = 78;
  18. const int COLORCHART_IMAGE_HEIGHT = 66;
  19. // color chart in cry engine is a special image data, with size 78x66, you may see in game screenshot which is defined by a rectangle
  20. // area with a yellow-black dash line boarder
  21. // Create color chart function is to read that block of image data and convert it to a color table then save it to another image
  22. // with size 256x16.
  23. class C3dLutColorChart
  24. {
  25. public:
  26. C3dLutColorChart() {}
  27. ~C3dLutColorChart() {};
  28. //generate default color chart data
  29. void GenerateDefault();
  30. //generate color chart data from input image
  31. bool GenerateFromInput(IImageObjectPtr image);
  32. //ouput the color chart data to an image object
  33. IImageObjectPtr GenerateChartImage();
  34. protected:
  35. //extract color chart data from specified location in an image
  36. void ExtractFromImageAt(IImageObjectPtr pImg, AZ::u32 x, AZ::u32 y);
  37. //find color chart location in an image
  38. static bool FindColorChart(const IImageObjectPtr pImg, AZ::u32& outLocX, AZ::u32& outLocY);
  39. //if there is a color chart at specified location
  40. static bool IsColorChartAt(AZ::u32 x, AZ::u32 y, void* pData, AZ::u32 pitch);
  41. private:
  42. enum EPrimaryShades
  43. {
  44. ePS_Red = 16,
  45. ePS_Green = 16,
  46. ePS_Blue = 16,
  47. ePS_NumColors = ePS_Red * ePS_Green * ePS_Blue
  48. };
  49. struct SColor
  50. {
  51. unsigned char r, g, b, _padding;
  52. };
  53. typedef AZStd::vector<SColor> ColorMapping;
  54. ColorMapping m_mapping;
  55. };
  56. void C3dLutColorChart::GenerateDefault()
  57. {
  58. m_mapping.reserve(ePS_NumColors);
  59. for (int b = 0; b < ePS_Blue; ++b)
  60. {
  61. for (int g = 0; g < ePS_Green; ++g)
  62. {
  63. for (int r = 0; r < ePS_Red; ++r)
  64. {
  65. SColor col;
  66. col.r = 255 * r / (ePS_Red);
  67. col.g = 255 * g / (ePS_Green);
  68. col.b = 255 * b / (ePS_Blue);
  69. int l = 255 - (col.r * 3 + col.g * 6 + col.b) / 10;
  70. col.r = col.g = col.b = (unsigned char)l;
  71. m_mapping.push_back(col);
  72. }
  73. }
  74. }
  75. }
  76. //find color chart location in a image
  77. bool C3dLutColorChart::FindColorChart(const IImageObjectPtr pImg, AZ::u32& outLocX, AZ::u32& outLocY)
  78. {
  79. const AZ::u32 width = pImg->GetWidth(0);
  80. const AZ::u32 height = pImg->GetHeight(0);
  81. //the origin image is too small to have a color chart
  82. if (width < COLORCHART_IMAGE_WIDTH || height < COLORCHART_IMAGE_HEIGHT)
  83. {
  84. return false;
  85. }
  86. AZ::u8* pData;
  87. AZ::u32 pitch;
  88. pImg->GetImagePointer(0, pData, pitch);
  89. //check all the posible start location on whether there might be a color chart
  90. for (AZ::u32 y = 0; y <= height - COLORCHART_IMAGE_HEIGHT; ++y)
  91. {
  92. for (AZ::u32 x = 0; x <= width - COLORCHART_IMAGE_WIDTH; ++x)
  93. {
  94. if (IsColorChartAt(x, y, pData, pitch))
  95. {
  96. outLocX = x;
  97. outLocY = y;
  98. return true;
  99. }
  100. }
  101. }
  102. return false;
  103. }
  104. bool C3dLutColorChart::GenerateFromInput(IImageObjectPtr image)
  105. {
  106. AZ::u32 outLocX, outLocY;
  107. if (FindColorChart(image, outLocX, outLocY))
  108. {
  109. ExtractFromImageAt(image, outLocX, outLocY);
  110. return true;
  111. }
  112. return false;
  113. }
  114. IImageObjectPtr C3dLutColorChart::GenerateChartImage()
  115. {
  116. const AZ::u32 mipCount = 1;
  117. IImageObjectPtr image( IImageObject::CreateImage(ePS_Red * ePS_Blue, ePS_Green, 1, ePixelFormat_R8G8B8A8));
  118. {
  119. AZ::u8* pData;
  120. AZ::u32 pitch;
  121. image->GetImagePointer(0, pData, pitch);
  122. size_t nSlicePitch = (pitch / ePS_Blue);
  123. AZ::u32 src = 0;
  124. AZ::u32 dst = 0;
  125. for (int b = 0; b < ePS_Blue; ++b)
  126. {
  127. for (int g = 0; g < ePS_Green; ++g)
  128. {
  129. AZ::u8* p = pData + g * pitch + b * nSlicePitch;
  130. for (int r = 0; r < ePS_Red; ++r)
  131. {
  132. const SColor& c = m_mapping[src];
  133. p[0] = c.r;
  134. p[1] = c.g;
  135. p[2] = c.b;
  136. p[3] = 255;
  137. ++src;
  138. p += 4;
  139. }
  140. }
  141. }
  142. }
  143. return image;
  144. }
  145. void C3dLutColorChart::ExtractFromImageAt(IImageObjectPtr image, AZ::u32 x, AZ::u32 y)
  146. {
  147. int ox = x + 1;
  148. int oy = y + 1;
  149. AZ::u8* pData;
  150. AZ::u32 pitch;
  151. image->GetImagePointer(0, pData, pitch);
  152. m_mapping.reserve(ePS_NumColors);
  153. for (int b = 0; b < ePS_Blue; ++b)
  154. {
  155. int px = ox + ePS_Red * (b % 4);
  156. int py = oy + ePS_Green * (b / 4);
  157. for (int g = 0; g < ePS_Green; ++g)
  158. {
  159. for (int r = 0; r < ePS_Red; ++r)
  160. {
  161. AZ::u8* p = pData + pitch * (py + g) + (px + r) * 4;
  162. SColor col;
  163. col.r = p[0];
  164. col.g = p[1];
  165. col.b = p[2];
  166. m_mapping.push_back(col);
  167. }
  168. }
  169. }
  170. }
  171. //check if image data at location x and y could be a color chart
  172. //based on if the boarder is dash lines with two pixel each segement
  173. //the idea and implementation are both coming from CryEngine.
  174. bool C3dLutColorChart::IsColorChartAt(AZ::u32 x, AZ::u32 y, void* pData, AZ::u32 pitch)
  175. {
  176. struct Color
  177. {
  178. private:
  179. int c[3];
  180. public:
  181. Color(AZ::u32 x, AZ::u32 y, void* pPixels, AZ::u32 pitch)
  182. {
  183. const uint8* p = (const uint8*)pPixels + pitch * y + x * 4;
  184. c[0] = p[0];
  185. c[1] = p[1];
  186. c[2] = p[2];
  187. }
  188. bool isSimilar(const Color& a, int maxDiff) const
  189. {
  190. return
  191. abs(a.c[0] - c[0]) <= maxDiff &&
  192. abs(a.c[1] - c[1]) <= maxDiff &&
  193. abs(a.c[2] - c[2]) <= maxDiff;
  194. }
  195. };
  196. const Color colorRef[2] =
  197. {
  198. Color(x, y, pData, pitch),
  199. Color(x + 2, y, pData, pitch)
  200. };
  201. // We require two colors of the border to be at least a bit different
  202. if (colorRef[0].isSimilar(colorRef[1], 15))
  203. {
  204. return false;
  205. }
  206. static const int kMaxDiff = 3;
  207. int refIdx = 0;
  208. //rectangle's top
  209. for (int i = 0; i < COLORCHART_IMAGE_WIDTH; i += 2)
  210. {
  211. if (!colorRef[refIdx].isSimilar(Color(x + i, y, pData, pitch), kMaxDiff) ||
  212. !colorRef[refIdx].isSimilar(Color(x + i + 1, y, pData, pitch), kMaxDiff))
  213. {
  214. return false;
  215. }
  216. refIdx ^= 1;
  217. }
  218. refIdx = 0;
  219. //left
  220. for (int i = 0; i < COLORCHART_IMAGE_HEIGHT; i += 2)
  221. {
  222. if (!colorRef[refIdx].isSimilar(Color(x, y + i, pData, pitch), kMaxDiff) ||
  223. !colorRef[refIdx].isSimilar(Color(x, y + i + 1, pData, pitch), kMaxDiff))
  224. {
  225. return false;
  226. }
  227. refIdx ^= 1;
  228. }
  229. refIdx = 0;
  230. //right
  231. for (int i = 0; i < COLORCHART_IMAGE_HEIGHT; i += 2)
  232. {
  233. if (!colorRef[refIdx].isSimilar(Color(x + COLORCHART_IMAGE_WIDTH - 1, y + i, pData, pitch), kMaxDiff) ||
  234. !colorRef[refIdx].isSimilar(Color(x + COLORCHART_IMAGE_WIDTH - 1, y + i + 1, pData, pitch), kMaxDiff))
  235. {
  236. return false;
  237. }
  238. refIdx ^= 1;
  239. }
  240. refIdx = 0;
  241. //bottom
  242. for (int i = 0; i < COLORCHART_IMAGE_WIDTH; i += 2)
  243. {
  244. if (!colorRef[refIdx].isSimilar(Color(x + i, y + COLORCHART_IMAGE_HEIGHT - 1, pData, pitch), kMaxDiff) ||
  245. !colorRef[refIdx].isSimilar(Color(x + i + 1, y + COLORCHART_IMAGE_HEIGHT - 1, pData, pitch), kMaxDiff))
  246. {
  247. return false;
  248. }
  249. refIdx ^= 1;
  250. }
  251. return true;
  252. }
  253. void ImageToProcess::CreateColorChart()
  254. {
  255. C3dLutColorChart colorChart;
  256. //get color chart data from source image.
  257. if (!colorChart.GenerateFromInput(m_img))
  258. {
  259. //if load from image failed then generate default color data
  260. colorChart.GenerateDefault();
  261. }
  262. //save color chart data to an image and save as current
  263. m_img = colorChart.GenerateChartImage();
  264. }
  265. }