Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ToHSV.cpp
1 /*
2  This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4  Copyright (C) 2003, 2004 (see file CONTACTS for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10  BIAS is free software; you can redistribute it and/or modify
11  it under the terms of the GNU Lesser General Public License as published by
12  the Free Software Foundation; either version 2.1 of the License, or
13  (at your option) any later version.
14 
15  BIAS is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with BIAS; if not, write to the Free Software
22  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 #include "ImageConvert.hh"
26 
27 using namespace BIAS;
28 
29 namespace BIAS
30 {
31 
32 template <class StorageType>
33 BIASImageBase_EXPORT
35  Image<StorageType> &dest)
36 {
37  int res = -1;
38 
39  if (dest.IsEmpty())
40  dest.Init(source.GetWidth(), source.GetHeight(), source.GetChannelCount(),
41  source.GetStorageType());
42 
43 #ifdef BIAS_DEBUG
44  if (!dest.SamePixelAndChannelCount(source)){
45  BIASERR("ImageConvert::ToHSV() sould be called with images of"\
46  <<" same size");
47  }
48 #endif
49 
50  switch (source.GetColorModel()) {
51  case ImageBase::CM_RGB:
52  res = RGBToHSV_(source,dest);
53  break;
54  default:
55  BIASERR("Image::ToHSV(): color model not implemented");
56  break;
57  }
59  return res;
60 }
61 
62 
63 
64 template <class StorageType>
66  Image<StorageType> &/*dest*/)
67 {
68  BIASERR("ImageConvert::RGBToHSV_ should be called from float image");
69  return -1;
70 }
71 
72 
73 template <>
75  Image<float> &dest)
76 
77 {
78 
79 
80 
81  BIASWARN("Unneccessary image copy operation. This may hurt performance.");
82  Image<float> source(source1);
83 
84 
85  register float *R = source.GetImageData();
86  register float *G = NULL , *B = NULL;
87  register float *ImageDataEnd =
88  R + source.GetPixelCount() * source.GetChannelCount();
89  register float *H = dest.GetImageData();
90  register float *S = NULL , *V = NULL;
91  register float Min = 0, Max = 0;
92  float MinVal = 0, MaxVal = 0;
93 
94  // scale image so RGB Values are between 0.0 and 1.0
95  // if necessairy
96  for (unsigned short int i = 0; i < dest.GetChannelCount(); i++){
97  source.GetMinMaxPixelValue(Min, Max, i);
98  if (Max > MaxVal)
99  MaxVal = Max;
100  if (Min < MinVal)
101  MinVal = Min;
102  }
103  if ( (MinVal < 0.0) || (MaxVal > 1.0) )
104  source.ScaleShiftBetween(0.0, 1.0);
105 
106  if (source.IsPlanar()){
107 
108  G = R + source.GetPixelCount();
109  B = G + source.GetPixelCount();
110  S = H + dest.GetPixelCount();
111  V = S + dest.GetPixelCount();
112  while (R < ImageDataEnd){
113  // calc Max and Min
114  if ( (*R >= *G) && (*R >= *B) ){
115  Max = *R;
116  if (*G <= *B)
117  Min = *G;
118  else
119  Min = *B;
120  } else if (*G >= *B){
121  Max = *G;
122  if (*B <= *R)
123  Min = *B;
124  else
125  Min = *R;
126  } else {
127  Max = *B;
128  if (*R <= *G)
129  Min = *R;
130  else
131  Min = *G;
132  }
133 
134  if (Max != Min){
135  // H (ue)
136  if (*R == Max)
137  *H = (*G - *B)/(Max - Min);
138  else if (*G == Max)
139  *H = 2.0f + (*B - *R)/(Max - Min);
140  else // (*B == Max)
141  *H = 4.0f + (*R - *G)/(Max - Min);
142  *H *= 60;
143  if (*H < 0)
144  *H += 360;
145  } else {
146  *H = 240;
147  }
148 
149  if (Max != 0.0){
150  // S (aturation)
151  *S = 1 - Min/Max;
152  // V (alue)
153  //*V = float(0.299* *R + 0.587* *G + 0.114* *B);
154  *V = Max;
155  } else {
156  *H = 240;
157  *S = 0;
158  *V = 0;
159  }
160 
161 
162  // increase pointers
163  H++;
164  S++;
165  V++;
166  R++;
167  G++;
168  B++;
169 
170  }
171  dest.SetInterleaved(false);
173 
174  } else { // source is interleaved
175  S = H + 1;
176  V = S + 1;
177  while (R < ImageDataEnd){
178 
179  // calulate min(R,G,B) and max(R,G,B)
180  Max = Min = R[0];
181  for (register int i = 1; i < 3; i++){
182  if ( Max < R[i])
183  Max = R[i];
184  if (Min > R[i])
185  Min = R[i];
186  }
187  G = R+1;
188  B = R+2;
189 
190  if (Max != Min) {
191  // H (ue)
192  if (*R == Max )
193  *H = (*G - *B)/(Max - Min);
194  else if (*G == Max )
195  *H = 2 + (*B - *R)/(Max - Min);
196  else // (*B == Max )
197  *H = 4 + (*R - *G)/(Max - Min);
198  *H *= 60;
199  if (*H < 0)
200  *H += 360;
201  } else {
202  *H = 0;
203  }
204 
205 
206  if (Max != 0.0){
207  // S (aturation)
208  *S = 1 - Min/Max;
209  // V (alue)
210 // *V = 0.299f* *R + 0.587f* *G + 0.114f* *B;
211  *V = Max;
212  } else {
213  *S = 0;
214  *V = 0;
215  }
216 
217  // increase pointers
218  H+=3;
219  S+=3;
220  V+=3;
221  R+=3;
222  }
223  dest.SetInterleaved(true);
225  }
226  return 0;
227 }
228 
229 
230 // H [0,255] 0 = red, 85 = green , 171 = blue
231 // saturation [0,255]
232 // value [0,255]
233 // fixed for interleaved by Daniel Grest, April 2003
234 template <>
236  Image<unsigned char> &dest)
237 {
238 #ifdef BIAS_DEBUG
239  if (source.GetColorModel() != ImageBase::CM_RGB){
240  BIASERR("source not in RGB format");
241  return -1;
242  }
243 #endif
244 
245  BIASASSERT(!source.IsEmpty());
246  BIASASSERT(!dest.IsEmpty());
247  BIASASSERT(source.GetWidth() == dest.GetWidth() );
248  BIASASSERT(source.GetHeight() == dest.GetHeight() );
249 
250 
251  register const unsigned char *R = source.GetImageData();
252  register const unsigned char *ImageDataEnd =
253  R + source.GetSizeByte();
254  register unsigned char *H = dest.GetImageData();
255  register const unsigned char *G = NULL, *B = NULL;
256  register unsigned char *S = NULL, *V = NULL;
257  //register unsigned char Min = 0, Max = 0;
258  unsigned char Min = 0;
259  unsigned char Max = 0;
260 
261  int TmpH=0;
262 
263  BIASASSERT( R != NULL);
264  BIASASSERT( H != NULL);
265 
266  if (source.IsPlanar()) {
267  G = R + source.GetPixelCount();
268  B = G + source.GetPixelCount();
269  S = H + dest.GetPixelCount();
270  V = S + dest.GetPixelCount();
271  while (R < ImageDataEnd){
272  // calc Max and Min
273  if ( (*R >= *G) && (*R >= *B) ){
274  Max = *R;
275  if (*G <= *B)
276  Min = *G;
277  else
278  Min = *B;
279  } else if (*G >= *B){
280  Max = *G;
281  if (*B <= *R)
282  Min = *B;
283  else
284  Min = *R;
285  } else {
286  Max = *B;
287  if (*R <= *G)
288  Min = *R;
289  else
290  Min = *G;
291  }
292 
293  if (Max != Min){
294  // H (ue)
295  if (*R == Max)
296  TmpH = 256 * (*G - *B)/(Max - Min);
297  else if (*G == Max)
298  TmpH = 512 + 256 * (*B - *R)/(Max - Min);
299  else // (*B == Max)
300  TmpH = 1024 + 256 * (*R - *G)/(Max - Min);
301  TmpH /= 6;
302  if (TmpH < 0)
303  *H = (unsigned char)(TmpH + 256);
304  else
305  *H = (unsigned char)TmpH;
306  } else {
307  *H = 171;
308  }
309 
310  if (Max != (unsigned char)0){
311  // S (aturation) [0,255]
312  *S = 255 - (unsigned char)(255.0 * (float)Min/(float)Max);
313  // V (alue)
314 // *V = (unsigned char)(0.299* (float)(*R) +
315 // 0.587* (float)(*G) + 0.114* (float)(*B) + 0.5);
316  *V = ((int)(*R) + (int)(*G) + (int)(*B)) / 3;
317 
318  } else {
319  *H = 171;
320  *S = 0;
321  *V = 0;
322  }
323 
324  // increase pointers
325  H++; S++; V++; R++; G++; B++;
326  }
327  dest.SetInterleaved(false);
329 
330  } else {// source is interleaved
331  // src
332  G = R + 1;
333  B = G + 1;
334  // dst
335  S = H + 1;
336  V = S + 1;
337  while (R < ImageDataEnd){
338  // calulate min(R,G,B) and max(R,G,B)
339  Max = Min = *R;
340  //jw
341  //Min = *R;
342  //Max = Min;
343  //BIASASSERT(R!=NULL);
344  //BIASASSERT(G!=NULL);
345  //BIASASSERT(B!=NULL);
346 
347  if (Max < *G) Max = *G;
348  if (Max < *B) Max = *B;
349  if (Min > *G) Min = *G;
350  if (Min > *B) Min = *B;
351 
352  if (Max != Min) {
353  // H (ue)
354  if (*R == Max)
355  TmpH = (256 * (*G - *B))/(Max - Min);
356  else if (*G == Max )
357  TmpH = 512 + (256 * (*B - *R))/(Max - Min);
358  else // (*B == Max )
359  TmpH = 1024 + (256 * (*R - *G))/(Max - Min);
360  TmpH /= 6;
361  if (TmpH < 0)
362  *H = (unsigned char)(TmpH + 256);
363  else
364  *H = (unsigned char)TmpH;
365  } else {
366  *H = 171;
367  }
368 
369 
370  if (Max != (unsigned char)0){
371  // S (aturation)
372  *S = (unsigned char)(255.0 * ((float)Max-(float)Min)/(float)Max);
373  // V (alue)
374 // *V = (unsigned char)(0.299* (float)(*R) +
375 // 0.587* (float)(*G) + 0.114* (float)(*B) + 0.5);
376  *V = ((int)(*R) + (int)(*G) + (int)(*B)) / 3;
377 
378  } else {
379  *H = 171;
380  *S = 0;
381  *V = 0;
382  }
383 
384  // increase pointers
385  H+=3;
386  S+=3;
387  V+=3;
388  R+=3;G+=3;B+=3;
389  }
390  dest.SetInterleaved(true);
392  }
393  return 0;
394 }
395 
396 template <class StorageType>
398 {
399  unsigned int nrOfPel = source.GetPixelCount();
400 
401  const StorageType *sp = source.GetImageData();
402  StorageType *dp = dest.GetImageData();
403 
404  if (source.IsPlanar()) {
405  BIASERR("Only for interleaved images!");
406  return -1;
407  }
408  if (source.GetChannelCount() != 3) {
409  BIASERR("Only for 3 channels!");
410  return -1;
411  }
412  unsigned int indexS = 0;
413  unsigned int indexD = 0;
414  StorageType h = 0, s = 0, v = 0, r = 0, g = 0, b = 0;
415  for (unsigned int x = 0; x < nrOfPel; x++) {
416  h = sp[indexS++];
417  s = sp[indexS++];
418  v = sp[indexS++];
419 
420  ImageConvert::HSVToRGB(h,s,v,r,g,b);
421 
422  dp[indexD++] = r;
423  dp[indexD++] = g;
424  dp[indexD++] = b;
425  }
426  return 0;
427 }
428 
429 
430 /* hue (0.0 to 360.0, is circular, 0=360)
431  s and v are from 0.0 - 1.0) */
432 template <class StorageType>
433 BIASImageBase_EXPORT
434 int BIAS::ImageConvert::HSVToRGB(const StorageType hs, const StorageType ss, StorageType vs,
435  StorageType &r, StorageType &g, StorageType &b)
436 {
437  float p1, p2, p3, i, f;
438  float xh;
439  float h = (float)hs;
440  float s = (float)ss;
441  float v = (float)vs;
442  /* (THIS LOOKS BACKWARDS) */
443  if (h == 360.0) h = 0.0;
444  xh = h / 60.0f; /* convert hue to be in 0,6 */
445  i = (float)floor((double)xh); /* i = greatest integer <= h */
446  f = xh - i; /* f = fractional part of h */
447  p1 = v * (1 - s);
448  p2 = v * (1 - (s * f));
449  p3 = v * (1 - (s * (1 - f)));
450  switch ((int) i)
451  {
452  case 0:
453  r = StorageType(v); g = StorageType(p3); b = StorageType(p1); break;
454  case 1:
455  r = StorageType(p2); g = StorageType(v); b = StorageType(p1); break;
456  case 2:
457  r = StorageType(p1); g = StorageType(v); b = StorageType(p3); break;
458  case 3:
459  r = StorageType(p1); g = StorageType(p2); b = StorageType(v); break;
460  case 4:
461  r = StorageType(p3); g = StorageType(p1); b = StorageType(v); break;
462  case 5:
463  r = StorageType(v); g = StorageType(p1); b = StorageType(p2); break;
464  }
465  /* Normalize the values to 255 */
466  r = (StorageType)(float)(r * 255.);
467  g = (StorageType)(float)(g * 255.);
468  b = (StorageType)(float)(b * 255.);
469  return 0;
470 }
471 
472 } // namespace BIAS
static int HSVToRGB_(const Image< StorageType > &source, Image< StorageType > &dest)
Definition: ToHSV.cpp:397
bool IsEmpty() const
check if ImageData_ points to allocated image buffer or not
Definition: ImageBase.hh:245
int ScaleShiftBetween(double Min, double Max)
scales and shifts image so afterwards every pixel has a value between Min and Max ...
Definition: Image.cpp:1118
void SetColorModel(EColorModel Model)
Definition: ImageBase.hh:561
unsigned int GetSizeByte() const
returns the nr.
Definition: ImageBase.hh:352
bool IsPlanar() const
Definition: ImageBase.hh:484
void GetMinMaxPixelValue(StorageType &min, StorageType &max, unsigned short int channel=0, unsigned int *mincoo=NULL, unsigned int *maxcoo=NULL) const
returns the minimal and maximal pixel value in channel only Finds minimum and maximum pixel value in ...
Definition: Image.cpp:802
unsigned int GetWidth() const
Definition: ImageBase.hh:312
void SetInterleaved(bool interleaved)
Definition: ImageBase.hh:568
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
Definition: ImageBase.hh:382
color values, 3 channels, order: red,green,blue
Definition: ImageBase.hh:131
static BIASImageBase_EXPORT int ToHSV(const Image< StorageType > &source, Image< StorageType > &dest)
Create a HSV converted copy of source image in this Release() and Init() are called if necessary...
Definition: ToHSV.cpp:34
static BIASImageBase_EXPORT int HSVToRGB(const StorageType h, const StorageType s, const StorageType v, StorageType &r, StorageType &g, StorageType &b)
conversion of one pixel in HSV to RGB colorspace
Definition: ToHSV.cpp:434
unsigned int GetHeight() const
Definition: ImageBase.hh:319
The image template class for specific storage types.
Definition: Image.hh:78
bool SamePixelAndChannelCount(const ImageBase &Image) const
checks if data area has same &quot;size&quot; as Image of other type
Definition: ImageBase.hh:73
void Init(unsigned int Width, unsigned int Height, unsigned int channels=1, enum EStorageType storageType=ST_unsignedchar, const bool interleaved=true)
calls Init from ImageBase storageType is ignored, just dummy argument
Definition: Image.cpp:421
const StorageType * GetImageData() const
overloaded GetImageData() from ImageBase
Definition: Image.hh:137
enum EColorModel GetColorModel() const
Definition: ImageBase.hh:407
enum EStorageType GetStorageType() const
Definition: ImageBase.hh:414
HSV, 3 channels, order: hue, sat , value.
Definition: ImageBase.hh:138
static int RGBToHSV_(const Image< StorageType > &source, Image< StorageType > &dest)
so far only implemented for StorageType=float
Definition: ToHSV.cpp:65
unsigned long int GetPixelCount() const
returns number of pixels in image
Definition: ImageBase.hh:422