libvisiontransfer  9.0.3
imageset.cpp
1 /*******************************************************************************
2  * Copyright (c) 2021 Nerian Vision GmbH
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *******************************************************************************/
14 
15 #include <iostream>
16 #include <fstream>
17 #include <stdexcept>
18 #include <cstring>
19 #include "visiontransfer/imageset.h"
20 
21 #ifdef _WIN32
22 #include <winsock2.h>
23 #else
24 #include <arpa/inet.h>
25 #endif
26 
27 using namespace visiontransfer;
28 
29 namespace visiontransfer {
30 
32  : width(0), height(0), qMatrix(NULL), timeSec(0), timeMicrosec(0),
33  seqNum(0), minDisparity(0), maxDisparity(0), subpixelFactor(16),
34  referenceCounter(NULL), numberOfImages(2), indexLeftImage(0), indexRightImage(1), indexDisparityImage(-1),
35  exposureTime(0), lastSyncPulseSec(0), lastSyncPulseMicrosec(0) {
36  for (int i=0; i<MAX_SUPPORTED_IMAGES; ++i) {
37  formats[i] = FORMAT_8_BIT_MONO;
38  data[i] = NULL;
39  rowStride[i] = 0;
40  }
41 }
42 
44  copyData(*this, other, true);
45 }
46 
47 ImageSet& ImageSet::operator= (ImageSet const& other) {
48  if(&other != this) {
49  decrementReference();
50  copyData(*this, other, true);
51  }
52  return *this;
53 }
54 
55 ImageSet::~ImageSet() {
56  decrementReference();
57 }
58 
59 void ImageSet::copyData(ImageSet& dest, const ImageSet& src, bool countRef) {
60  dest.width = src.width;
61  dest.height = src.height;
62 
63  dest.numberOfImages = src.numberOfImages;
64  for(int i=0; i<src.numberOfImages; i++) {
65  dest.rowStride[i] = src.rowStride[i];
66  dest.formats[i] = src.formats[i];
67  dest.data[i] = src.data[i];
68  }
69 
70  dest.qMatrix = src.qMatrix;
71  dest.timeSec = src.timeSec;
72  dest.timeMicrosec = src.timeMicrosec;
73  dest.seqNum = src.seqNum;
74  dest.minDisparity = src.minDisparity;
75  dest.maxDisparity = src.maxDisparity;
76  dest.subpixelFactor = src.subpixelFactor;
77  dest.referenceCounter = src.referenceCounter;
78  dest.numberOfImages = src.numberOfImages;
79  dest.indexLeftImage = src.indexLeftImage;
80  dest.indexRightImage = src.indexRightImage;
81  dest.indexDisparityImage = src.indexDisparityImage;
82  dest.exposureTime = src.exposureTime;
83  dest.lastSyncPulseSec = src.lastSyncPulseSec;
84  dest.lastSyncPulseMicrosec = src.lastSyncPulseMicrosec;
85 
86  if(dest.referenceCounter != nullptr && countRef) {
87  (*dest.referenceCounter)++;
88  }
89 }
90 
91 void ImageSet::decrementReference() {
92  if(referenceCounter != nullptr && --(*referenceCounter) == 0) {
93  for (int i=0; i<getNumberOfImages(); ++i) {
94  delete []data[i];
95  data[i] = nullptr;
96  }
97  delete []qMatrix;
98  delete referenceCounter;
99 
100  qMatrix = nullptr;
101  referenceCounter = nullptr;
102  }
103 }
104 
105 void ImageSet::writePgmFile(int imageNumber, const char* fileName) const {
106  if(imageNumber < 0 || imageNumber >= getNumberOfImages()) {
107  throw std::runtime_error("Illegal image number!");
108  }
109 
110  std::fstream strm(fileName, std::ios::out | std::ios::binary);
111 
112  // Write PGM / PBM header
113  int type, maxVal, bytesPerChannel, channels;
114  switch(formats[imageNumber]) {
115  case FORMAT_8_BIT_MONO:
116  type = 5;
117  maxVal = 255;
118  bytesPerChannel = 1;
119  channels = 1;
120  break;
121  case FORMAT_12_BIT_MONO:
122  type = 5;
123  maxVal = 4095;
124  bytesPerChannel = 2;
125  channels = 1;
126  break;
127  case FORMAT_8_BIT_RGB:
128  type = 6;
129  maxVal = 255;
130  bytesPerChannel = 1;
131  channels = 3;
132  break;
133  default:
134  throw std::runtime_error("Illegal pixel format!");
135  }
136 
137  strm << "P" << type << " " << width << " " << height << " " << maxVal << std::endl;
138 
139  // Write image data
140  for(int y = 0; y < height; y++) {
141  for(int x = 0; x < width*channels; x++) {
142  unsigned char* pixel = &data[imageNumber][y*rowStride[imageNumber] + x*bytesPerChannel];
143  if(bytesPerChannel == 2) {
144  // Swap endianess
145  unsigned short swapped = htons(*reinterpret_cast<unsigned short*>(pixel));
146  strm.write(reinterpret_cast<char*>(&swapped), sizeof(swapped));
147  } else {
148  strm.write(reinterpret_cast<char*>(pixel), 1);
149  }
150  }
151  }
152 }
153 
155  switch(format) {
156  case FORMAT_8_BIT_MONO: return 8;
157  case FORMAT_8_BIT_RGB: return 24;
158  case FORMAT_12_BIT_MONO: return 12;
159  default: throw std::runtime_error("Invalid image format!");
160  }
161 }
162 
164  dest.decrementReference();
165  copyData(dest, *this, false);
166 
167  dest.qMatrix = new float[16];
168  memcpy(const_cast<float*>(dest.qMatrix), qMatrix, sizeof(float)*16);
169 
170  for(int i=0; i<getNumberOfImages(); i++) {
171  int bytesPixel = getBytesPerPixel(i);
172 
173  dest.rowStride[i] = width*bytesPixel;
174  dest.data[i] = new unsigned char[height*dest.rowStride[i]];
175 
176  // Convert possibly different row strides
177  for(int y = 0; y < height; y++) {
178  memcpy(&dest.data[i][y*dest.rowStride[i]], &data[i][y*rowStride[i]],
179  dest.rowStride[i]);
180  }
181  }
182 
183  dest.referenceCounter = new int;
184  (*dest.referenceCounter) = 1;
185 }
186 
188  switch(format) {
189  case FORMAT_8_BIT_MONO: return 1;
190  case FORMAT_8_BIT_RGB: return 3;
191  case FORMAT_12_BIT_MONO: return 2;
192  default: throw std::runtime_error("Invalid image format!");
193  }
194 }
195 
197  assert(imageNumber >= 0 && imageNumber < getNumberOfImages());
198  if (imageNumber == getIndexOf(ImageSet::ImageType::IMAGE_LEFT)) return ImageSet::ImageType::IMAGE_LEFT;
199  if (imageNumber == getIndexOf(ImageSet::ImageType::IMAGE_RIGHT)) return ImageSet::ImageType::IMAGE_RIGHT;
200  if (imageNumber == getIndexOf(ImageSet::ImageType::IMAGE_DISPARITY)) return ImageSet::ImageType::IMAGE_DISPARITY;
201  throw std::runtime_error("Invalid image number for getImageType!");
202 }
203 
204 void ImageSet::setImageDisparityPair(bool dispPair) {
205  if (getNumberOfImages() != 2) throw std::runtime_error("setImageDisparityPair is only supported for two-image sets");
206  // Let index assignments directly follow the mode
207  indexLeftImage = 0;
208  indexRightImage = dispPair ? -1 : 1;
209  indexDisparityImage = dispPair ? 1 : -1;
210 }
211 
212 int ImageSet::getIndexOf(ImageType what, bool throwIfNotFound) const {
213  int idx = -1;
214  switch(what) {
215  case IMAGE_LEFT: {
216  idx = indexLeftImage;
217  break;
218  }
219  case IMAGE_RIGHT: {
220  idx = indexRightImage;
221  break;
222  }
223  case IMAGE_DISPARITY: {
224  idx = indexDisparityImage;
225  break;
226  }
227  default:
228  throw std::runtime_error("Invalid ImageType for query!");
229  }
230  if (throwIfNotFound && (idx==-1)) throw std::runtime_error("ImageSet does not contain the queried ImageType");
231  return idx;
232 }
233 
234 void ImageSet::setIndexOf(ImageType what, int idx) {
235  switch(what) {
236  case IMAGE_LEFT: {
237  indexLeftImage = idx;
238  break;
239  }
240  case IMAGE_RIGHT: {
241  indexRightImage = idx;
242  break;
243  }
244  case IMAGE_DISPARITY: {
245  indexDisparityImage = idx;
246  break;
247  }
248  default:
249  throw std::runtime_error("Invalid ImageType for setIndexOf!");
250  }
251 }
252 } // namespace
253 
int getBitsPerPixel(int imageNumber) const
Returns the number of bits that are required to store one image pixel.
Definition: imageset.h:383
void writePgmFile(int imageNumber, const char *fileName) const
Writes one image of the set to a PGM or PPM file.
Definition: imageset.cpp:105
int getIndexOf(ImageType what, bool throwIfNotFound=false) const
Returns the index of a specific image type.
Definition: imageset.cpp:212
int getNumberOfImages() const
Returns the number of images in this set.
Definition: imageset.h:404
int getBytesPerPixel(int imageNumber) const
Returns the number of bytes that are required to store one image pixel.
Definition: imageset.h:372
ImageSet()
Default constructor creating an image set with no pixel data.
Definition: imageset.cpp:31
void copyTo(ImageSet &dest)
Makes a deep copy of this image set.
Definition: imageset.cpp:163
ImageType
Supported image types.
Definition: imageset.h:67
ImageType getImageType(int imageNumber) const
Returns the ImageType of the specified channel.
Definition: imageset.cpp:196
ImageFormat
Image formats that can be transferred.
Definition: imageset.h:44
A set of one to three images, but usually two (the left camera image and the disparity map)...
Definition: imageset.h:38
void setIndexOf(ImageType what, int idx)
Assign an image index to a specified ImageType, -1 to disable.
Definition: imageset.cpp:234
Nerian Vision Technologies