Visual Servoing Platform  version 3.6.1 under development (2024-10-18)
vpImage_lut.h
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Image handling.
32  */
33 
34 #ifndef VP_IMAGE_LUT_H
35 #define VP_IMAGE_LUT_H
36 
37 // Warning: this file shouldn't be included by the user. Internal usage only to reduce length of vpImage.h
38 
39 #if defined(VISP_HAVE_THREADS)
40 namespace
41 {
42 struct vpImageLut_Param_t
43 {
44  unsigned int m_start_index;
45  unsigned int m_end_index;
46 
47  unsigned char m_lut[256];
48  unsigned char *m_bitmap;
49 
50  vpImageLut_Param_t() : m_start_index(0), m_end_index(0), m_lut(), m_bitmap(nullptr) { }
51 
52  vpImageLut_Param_t(unsigned int start_index, unsigned int end_index, unsigned char *bitmap)
53  : m_start_index(start_index), m_end_index(end_index), m_lut(), m_bitmap(bitmap)
54  { }
55 };
56 
57 void performLutThread(vpImageLut_Param_t *imageLut_param)
58 {
59  unsigned int start_index = imageLut_param->m_start_index;
60  unsigned int end_index = imageLut_param->m_end_index;
61 
62  unsigned char *bitmap = imageLut_param->m_bitmap;
63 
64  unsigned char *ptrStart = bitmap + start_index;
65  unsigned char *ptrEnd = bitmap + end_index;
66  unsigned char *ptrCurrent = ptrStart;
67 
68  if (end_index - start_index >= 8) {
69  // Unroll loop version
70  for (; ptrCurrent <= ptrEnd - 8;) {
71  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
72  ++ptrCurrent;
73 
74  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
75  ++ptrCurrent;
76 
77  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
78  ++ptrCurrent;
79 
80  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
81  ++ptrCurrent;
82 
83  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
84  ++ptrCurrent;
85 
86  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
87  ++ptrCurrent;
88 
89  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
90  ++ptrCurrent;
91 
92  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
93  ++ptrCurrent;
94  }
95  }
96 
97  for (; ptrCurrent != ptrEnd; ++ptrCurrent) {
98  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
99  }
100 }
101 
102 struct vpImageLutRGBa_Param_t
103 {
104  unsigned int m_start_index;
105  unsigned int m_end_index;
106 
107  VISP_NAMESPACE_ADDRESSING vpRGBa m_lut[256];
108  unsigned char *m_bitmap;
109 
110  vpImageLutRGBa_Param_t() : m_start_index(0), m_end_index(0), m_lut(), m_bitmap(nullptr) { }
111 
112  vpImageLutRGBa_Param_t(unsigned int start_index, unsigned int end_index, unsigned char *bitmap)
113  : m_start_index(start_index), m_end_index(end_index), m_lut(), m_bitmap(bitmap)
114  { }
115 };
116 
117 void performLutRGBaThread(vpImageLutRGBa_Param_t *imageLut_param)
118 {
119  unsigned int start_index = imageLut_param->m_start_index;
120  unsigned int end_index = imageLut_param->m_end_index;
121 
122  unsigned char *bitmap = imageLut_param->m_bitmap;
123 
124  unsigned char *ptrStart = bitmap + start_index * 4;
125  unsigned char *ptrEnd = bitmap + end_index * 4;
126  unsigned char *ptrCurrent = ptrStart;
127 
128  if (end_index - start_index >= 4 * 2) {
129  // Unroll loop version
130  for (; ptrCurrent <= ptrEnd - 4 * 2;) {
131  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].R;
132  ptrCurrent++;
133  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].G;
134  ptrCurrent++;
135  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].B;
136  ptrCurrent++;
137  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].A;
138  ptrCurrent++;
139 
140  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].R;
141  ptrCurrent++;
142  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].G;
143  ptrCurrent++;
144  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].B;
145  ptrCurrent++;
146  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].A;
147  ptrCurrent++;
148  }
149  }
150 
151  while (ptrCurrent != ptrEnd) {
152  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].R;
153  ptrCurrent++;
154 
155  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].G;
156  ptrCurrent++;
157 
158  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].B;
159  ptrCurrent++;
160 
161  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].A;
162  ptrCurrent++;
163  }
164 }
165 } // namespace
166 #endif
167 
176 template <class Type> void vpImage<Type>::performLut(const Type(&)[256], unsigned int)
177 {
178  std::cerr << "Not implemented !" << std::endl;
179 }
180 
191 template <> inline void vpImage<unsigned char>::performLut(const unsigned char(&lut)[256], unsigned int nbThreads)
192 {
193  unsigned int size = getWidth() * getHeight();
194  unsigned char *ptrStart = static_cast<unsigned char *>(bitmap);
195  unsigned char *ptrEnd = ptrStart + size;
196  unsigned char *ptrCurrent = ptrStart;
197 
198  bool use_single_thread = ((nbThreads == 0) || (nbThreads == 1));
199 #if !defined(VISP_HAVE_THREADS)
200  use_single_thread = true;
201 #endif
202 
203  if ((!use_single_thread) && (getSize() <= nbThreads)) {
204  use_single_thread = true;
205  }
206 
207  if (use_single_thread) {
208  // Single thread
209 
210  while (ptrCurrent != ptrEnd) {
211  *ptrCurrent = lut[*ptrCurrent];
212  ++ptrCurrent;
213  }
214  }
215  else {
216 #if defined(VISP_HAVE_THREADS)
217  // Multi-threads
218  std::vector<std::thread *> threadpool;
219  std::vector<vpImageLut_Param_t *> imageLutParams;
220 
221  unsigned int image_size = getSize();
222  unsigned int step = image_size / nbThreads;
223  unsigned int last_step = image_size - step * (nbThreads - 1);
224 
225  for (unsigned int index = 0; index < nbThreads; ++index) {
226  unsigned int start_index = index * step;
227  unsigned int end_index = (index + 1) * step;
228 
229  if (index == nbThreads - 1) {
230  end_index = start_index + last_step;
231  }
232 
233  vpImageLut_Param_t *imageLut_param = new vpImageLut_Param_t(start_index, end_index, bitmap);
234  memcpy(imageLut_param->m_lut, lut, 256 * sizeof(unsigned char));
235 
236  imageLutParams.push_back(imageLut_param);
237 
238  // Start the threads
239  std::thread *imageLut_thread = new std::thread(&performLutThread, imageLut_param);
240  threadpool.push_back(imageLut_thread);
241  }
242 
243  for (size_t cpt = 0; cpt < threadpool.size(); ++cpt) {
244  // Wait until thread ends up
245  threadpool[cpt]->join();
246  }
247 
248  // Delete
249  for (size_t cpt = 0; cpt < threadpool.size(); ++cpt) {
250  delete threadpool[cpt];
251  }
252 
253  for (size_t cpt = 0; cpt < imageLutParams.size(); ++cpt) {
254  delete imageLutParams[cpt];
255  }
256 #endif
257  }
258 }
259 
270 template <> inline void vpImage<vpRGBa>::performLut(const vpRGBa(&lut)[256], unsigned int nbThreads)
271 {
272  unsigned int size = getWidth() * getHeight();
273  unsigned char *ptrStart = reinterpret_cast<unsigned char *>(bitmap);
274  unsigned char *ptrEnd = ptrStart + (size * 4);
275  unsigned char *ptrCurrent = ptrStart;
276 
277  bool use_single_thread = ((nbThreads == 0) || (nbThreads == 1));
278 #if !defined(VISP_HAVE_THREADS)
279  use_single_thread = true;
280 #endif
281 
282  if ((!use_single_thread) && (getSize() <= nbThreads)) {
283  use_single_thread = true;
284  }
285 
286  if (use_single_thread) {
287  // Single thread
288  while (ptrCurrent != ptrEnd) {
289  *ptrCurrent = lut[*ptrCurrent].R;
290  ++ptrCurrent;
291 
292  *ptrCurrent = lut[*ptrCurrent].G;
293  ++ptrCurrent;
294 
295  *ptrCurrent = lut[*ptrCurrent].B;
296  ++ptrCurrent;
297 
298  *ptrCurrent = lut[*ptrCurrent].A;
299  ++ptrCurrent;
300  }
301  }
302  else {
303 #if defined(VISP_HAVE_THREADS)
304  // Multi-threads
305  std::vector<std::thread *> threadpool;
306  std::vector<vpImageLutRGBa_Param_t *> imageLutParams;
307 
308  unsigned int image_size = getSize();
309  unsigned int step = image_size / nbThreads;
310  unsigned int last_step = image_size - step * (nbThreads - 1);
311 
312  for (unsigned int index = 0; index < nbThreads; ++index) {
313  unsigned int start_index = index * step;
314  unsigned int end_index = (index + 1) * step;
315 
316  if (index == nbThreads - 1) {
317  end_index = start_index + last_step;
318  }
319 
320  vpImageLutRGBa_Param_t *imageLut_param = new vpImageLutRGBa_Param_t(start_index, end_index, (unsigned char *)bitmap);
321  memcpy(static_cast<void *>(imageLut_param->m_lut), lut, 256 * sizeof(vpRGBa));
322 
323  imageLutParams.push_back(imageLut_param);
324 
325  // Start the threads
326  std::thread *imageLut_thread = new std::thread(&performLutRGBaThread, imageLut_param);
327  threadpool.push_back(imageLut_thread);
328  }
329 
330  for (size_t cpt = 0; cpt < threadpool.size(); ++cpt) {
331  // Wait until thread ends up
332  threadpool[cpt]->join();
333  }
334 
335  // Delete
336  for (size_t cpt = 0; cpt < threadpool.size(); ++cpt) {
337  delete threadpool[cpt];
338  }
339 
340  for (size_t cpt = 0; cpt < imageLutParams.size(); ++cpt) {
341  delete imageLutParams[cpt];
342  }
343 #endif
344  }
345 }
346 
347 #endif
unsigned int getWidth() const
Definition: vpImage.h:242
void performLut(const Type(&lut)[256], unsigned int nbThreads=1)
Definition: vpImage_lut.h:176
unsigned int getSize() const
Definition: vpImage.h:221
Type * bitmap
points toward the bitmap
Definition: vpImage.h:135
unsigned int getHeight() const
Definition: vpImage.h:181
Definition: vpRGBa.h:65