1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
4 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 **************************************************************************/
27 // File: vogl_image_utils.h
30 #include "vogl_core.h"
31 #include "vogl_image.h"
32 #include "vogl_data_stream_serializer.h"
33 #include "vogl_matrix.h"
43 cReadFlagForceSTB = 1,
44 cReadFlagsAllFlags = 1
47 bool read_from_stream_stb(data_stream_serializer &serializer, image_u8 &img);
48 bool read_from_stream_jpgd(data_stream_serializer &serializer, image_u8 &img);
49 bool read_from_stream(image_u8 &dest, data_stream_serializer &serializer, uint read_flags = 0);
50 bool read_from_file(image_u8 &dest, const char *pFilename, uint read_flags = 0);
52 // Reads texture from memory, results returned stb_image.c style.
53 // *pActual_comps is set to 1, 3, or 4. req_comps must range from 1-4.
54 uint8 *read_from_memory(const uint8 *pImage, int nSize, int *pWidth, int *pHeight, int *pActualComps, int req_comps, const char *pFilename);
58 cWriteFlagIgnoreAlpha = 0x00000001,
59 cWriteFlagGrayscale = 0x00000002,
60 cWriteFlagJPEGH1V1 = 0x00010000,
61 cWriteFlagJPEGH2V1 = 0x00020000,
62 cWriteFlagJPEGH2V2 = 0x00040000,
63 cWriteFlagJPEGTwoPass = 0x00080000,
64 cWriteFlagJPEGNoChromaDiscrim = 0x00100000,
65 cWriteFlagJPEGQualityLevelMask = 0xFF000000,
66 cWriteFlagJPEGQualityLevelShift = 24,
71 cJPEGMinQualityLevel = 1,
72 cJPEGMaxQualityLevel = 100
75 inline uint create_jpeg_write_flags(uint base_flags, uint quality_level)
77 VOGL_ASSERT(quality_level <= 100);
78 return base_flags | ((quality_level << cWriteFlagJPEGQualityLevelShift) & cWriteFlagJPEGQualityLevelMask);
81 const int cLumaComponentIndex = -1;
83 bool write_to_file(const char *pFilename, const image_u8 &img, uint write_flags = 0, int grayscale_comp_index = cLumaComponentIndex);
84 bool write_to_file(const char *pFilename, const image_f &img, const vec4F &l, const vec4F &h, uint write_flags = 0, int grayscale_comp_index = cLumaComponentIndex);
86 bool has_alpha(const image_u8 &img);
87 bool is_normal_map(const image_u8 &img, const char *pFilename = NULL);
88 void renorm_normal_map(image_u8 &img);
90 struct resample_params
95 m_pFilter("lanczos4"),
101 m_source_gamma(2.2f), // 1.75f
102 m_multithreaded(true),
110 const char *m_pFilter;
111 float m_filter_scale;
116 float m_source_gamma;
117 bool m_multithreaded;
122 bool resample_single_thread(const image_u8 &src, image_u8 &dst, const resample_params ¶ms);
123 bool resample_multithreaded(const image_u8 &src, image_u8 &dst, const resample_params ¶ms);
124 bool resample(const image_u8 &src, image_u8 &dst, const resample_params ¶ms);
125 bool resample(const image_f &src, image_f &dst, const resample_params ¶ms);
127 bool compute_delta(image_u8 &dest, const image_u8 &a, const image_u8 &b, uint scale = 2);
134 utils::zero_this(this);
137 void print(const char *pName) const;
139 // If num_channels==0, luma error is computed.
140 // If pHist != NULL, it must point to a 256 entry array.
141 bool compute(const image_u8 &a, const image_u8 &b, uint first_channel, uint num_channels, bool average_component_error = true);
146 double mRootMeanSquared;
151 inline bool operator==(const error_metrics &other) const
153 return mPeakSNR == other.mPeakSNR;
156 inline bool operator<(const error_metrics &other) const
158 return mPeakSNR < other.mPeakSNR;
161 inline bool operator>(const error_metrics &other) const
163 return mPeakSNR > other.mPeakSNR;
167 void print_image_metrics(const image_u8 &src_img, const image_u8 &dst_img);
169 double compute_block_ssim(uint n, const uint8 *pX, const uint8 *pY);
170 double compute_ssim(const image_u8 &a, const image_u8 &b, int channel_index);
171 void print_ssim(const image_u8 &src_img, const image_u8 &dst_img);
175 cConversion_Invalid = -1,
177 cConversion_From_CCxY,
179 cConversion_From_xGxR,
181 cConversion_From_xGBR,
183 cConversion_From_AGBR,
184 cConversion_XY_to_XYZ,
186 cConversion_A_To_RGBA,
187 cConversion_Y_To_RGB,
192 void convert_image(image_u8 &img, conversion_type conv_type);
194 template <typename image_type>
195 inline uint8 *pack_image(const image_type &img, const pixel_packer &packer, uint &n)
199 if (!packer.is_valid())
202 const uint width = img.get_width(), height = img.get_height();
203 uint dst_pixel_stride = packer.get_pixel_stride();
204 uint dst_pitch = width * dst_pixel_stride;
206 n = dst_pitch * height;
208 uint8 *pImage = static_cast<uint8 *>(vogl_malloc(n));
210 uint8 *pDst = pImage;
211 for (uint y = 0; y < height; y++)
213 const typename image_type::color_t *pSrc = img.get_scanline(y);
214 for (uint x = 0; x < width; x++)
215 pDst = (uint8 *)packer.pack(*pSrc++, pDst);
221 image_utils::conversion_type get_conversion_type(bool cooking, pixel_format fmt);
223 image_utils::conversion_type get_image_conversion_type_from_vogl_format(vogl_format fmt);
225 double compute_std_dev(uint n, const color_quad_u8 *pPixels, uint first_channel, uint num_channels);
227 uint8 *read_image_from_memory(const uint8 *pImage, int nSize, int *pWidth, int *pHeight, int *pActualComps, int req_comps, const char *pFilename);
230 void create_normalized_convolution_matrix(matrix<M, M, float> &weights, const float *pSrc_weights)
238 const int HM = M / 2;
239 VOGL_ASSERT(HM * 2 + 1 == M);
242 for (int yd = -HM; yd <= HM; yd++)
244 float yw = pSrc_weights[yd + HM];
245 for (int xd = -HM; xd <= HM; xd++)
247 float xw = pSrc_weights[xd + HM];
249 weights[yd + HM][xd + HM] = w;
254 VOGL_ASSERT(tw > 0.0f);
258 inline void convolution_filter(image_u8 &dst, const image_u8 &src, const float *pWeights, uint M, uint N, bool wrapping);
260 // M = num rows (Y), N = num cols (X)
261 template <uint M, uint N>
262 void convolution_filter(image_u8 &dst, const image_u8 &src, const matrix<M, N, float> &weights, bool wrapping)
264 convolution_filter(dst, src, &weights[0][0], M, N, wrapping);
267 void convolution_filter(image_f &dst, const image_f &src, const float *pWeights, uint M, uint N, bool wrapping);
269 // M = num rows (Y), N = num cols (X)
270 template <uint M, uint N>
271 inline void convolution_filter(image_f &dst, const image_f &src, const matrix<M, N, float> &weights, bool wrapping)
273 convolution_filter(dst, src, &weights[0][0], M, N, wrapping);
276 bool forward_fourier_transform(const image_u8 &src, image_u8 &dst, uint comp_mask = 0xF);
278 void gaussian_filter(image_u8 &dst, const image_u8 &orig_img, uint width_divisor, uint height_divisor, uint odd_filter_width, float sigma_sqr, bool wrapping);
280 } // namespace image_utils