libvisiontransfer  8.1.0
imageset.cpp
1 /*******************************************************************************
2  * Copyright (c) 2020 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  for (int i=0; i<MAX_SUPPORTED_IMAGES; ++i) {
36  formats[i] = FORMAT_8_BIT_MONO;
37  data[i] = NULL;
38  rowStride[i] = 0;
39  }
40 }
41 
43  copyData(*this, other, true);
44 }
45 
46 ImageSet& ImageSet::operator= (ImageSet const& other) {
47  if(&other != this) {
48  decrementReference();
49  copyData(*this, other, true);
50  }
51  return *this;
52 }
53 
54 ImageSet::~ImageSet() {
55  decrementReference();
56 }
57 
58 void ImageSet::copyData(ImageSet& dest, const ImageSet& src, bool countRef) {
59  dest.width = src.width;
60  dest.height = src.height;
61 
62  dest.numberOfImages = src.numberOfImages;
63  for(int i=0; i<src.numberOfImages; i++) {
64  dest.rowStride[i] = src.rowStride[i];
65  dest.formats[i] = src.formats[i];
66  dest.data[i] = src.data[i];
67  }
68 
69  dest.qMatrix = src.qMatrix;
70  dest.timeSec = src.timeSec;
71  dest.timeMicrosec = src.timeMicrosec;
72  dest.seqNum = src.seqNum;
73  dest.minDisparity = src.minDisparity;
74  dest.maxDisparity = src.maxDisparity;
75  dest.subpixelFactor = src.subpixelFactor;
76  dest.referenceCounter = src.referenceCounter;
77  dest.numberOfImages = src.numberOfImages;
78  dest.indexLeftImage = src.indexLeftImage;
79  dest.indexRightImage = src.indexRightImage;
80  dest.indexDisparityImage = src.indexDisparityImage;
81 
82  if(dest.referenceCounter != nullptr && countRef) {
83  (*dest.referenceCounter)++;
84  }
85 }
86 
87 void ImageSet::decrementReference() {
88  if(referenceCounter != nullptr && --(*referenceCounter) == 0) {
89  for (int i=0; i<getNumberOfImages(); ++i) {
90  delete []data[i];
91  data[i] = nullptr;
92  }
93  delete []qMatrix;
94  delete referenceCounter;
95 
96  qMatrix = nullptr;
97  referenceCounter = nullptr;
98  }
99 }
100 
101 void ImageSet::writePgmFile(int imageNumber, const char* fileName) const {
102  if(imageNumber < 0 || imageNumber >= getNumberOfImages()) {
103  throw std::runtime_error("Illegal image number!");
104  }
105 
106  std::fstream strm(fileName, std::ios::out | std::ios::binary);
107 
108  // Write PGM / PBM header
109  int type, maxVal, bytesPerChannel, channels;
110  switch(formats[imageNumber]) {
111  case FORMAT_8_BIT_MONO:
112  type = 5;
113  maxVal = 255;
114  bytesPerChannel = 1;
115  channels = 1;
116  break;
117  case FORMAT_12_BIT_MONO:
118  type = 5;
119  maxVal = 4095;
120  bytesPerChannel = 2;
121  channels = 1;
122  break;
123  case FORMAT_8_BIT_RGB:
124  type = 6;
125  maxVal = 255;
126  bytesPerChannel = 1;
127  channels = 3;
128  break;
129  default:
130  throw std::runtime_error("Illegal pixel format!");
131  }
132 
133  strm << "P" << type << " " << width << " " << height << " " << maxVal << std::endl;
134 
135  // Write image data
136  for(int y = 0; y < height; y++) {
137  for(int x = 0; x < width*channels; x++) {
138  unsigned char* pixel = &data[imageNumber][y*rowStride[imageNumber] + x*bytesPerChannel];
139  if(bytesPerChannel == 2) {
140  // Swap endianess
141  unsigned short swapped = htons(*reinterpret_cast<unsigned short*>(pixel));
142  strm.write(reinterpret_cast<char*>(&swapped), sizeof(swapped));
143  } else {
144  strm.write(reinterpret_cast<char*>(pixel), 1);
145  }
146  }
147  }
148 }
149 
151  switch(format) {
152  case FORMAT_8_BIT_MONO: return 8;
153  case FORMAT_8_BIT_RGB: return 24;
154  case FORMAT_12_BIT_MONO: return 12;
155  default: throw std::runtime_error("Invalid image format!");
156  }
157 }
158 
160  dest.decrementReference();
161  copyData(dest, *this, false);
162 
163  dest.qMatrix = new float[16];
164  memcpy(const_cast<float*>(dest.qMatrix), qMatrix, sizeof(float)*16);
165 
166  for(int i=0; i<getNumberOfImages(); i++) {
167  int bytesPixel = getBytesPerPixel(i);
168 
169  dest.rowStride[i] = width*bytesPixel;
170  dest.data[i] = new unsigned char[height*dest.rowStride[i]];
171 
172  // Convert possibly different row strides
173  for(int y = 0; y < height; y++) {
174  memcpy(&dest.data[i][y*dest.rowStride[i]], &data[i][y*rowStride[i]],
175  dest.rowStride[i]);
176  }
177  }
178 
179  dest.referenceCounter = new int;
180  (*dest.referenceCounter) = 1;
181 }
182 
184  switch(format) {
185  case FORMAT_8_BIT_MONO: return 1;
186  case FORMAT_8_BIT_RGB: return 3;
187  case FORMAT_12_BIT_MONO: return 2;
188  default: throw std::runtime_error("Invalid image format!");
189  }
190 }
191 
193  assert(imageNumber >= 0 && imageNumber < getNumberOfImages());
194  if (imageNumber == getIndexOf(ImageSet::ImageType::IMAGE_LEFT)) return ImageSet::ImageType::IMAGE_LEFT;
195  if (imageNumber == getIndexOf(ImageSet::ImageType::IMAGE_RIGHT)) return ImageSet::ImageType::IMAGE_RIGHT;
196  if (imageNumber == getIndexOf(ImageSet::ImageType::IMAGE_DISPARITY)) return ImageSet::ImageType::IMAGE_DISPARITY;
197  throw std::runtime_error("Invalid image number for getImageType!");
198 }
199 
200 void ImageSet::setImageDisparityPair(bool dispPair) {
201  if (getNumberOfImages() != 2) throw std::runtime_error("setImageDisparityPair is only supported for two-image sets");
202  // Let index assignments directly follow the mode
203  indexLeftImage = 0;
204  indexRightImage = dispPair ? -1 : 1;
205  indexDisparityImage = dispPair ? 1 : -1;
206 }
207 
208 int ImageSet::getIndexOf(ImageType what, bool throwIfNotFound) const {
209  int idx = -1;
210  switch(what) {
211  case IMAGE_LEFT: {
212  idx = indexLeftImage;
213  break;
214  }
215  case IMAGE_RIGHT: {
216  idx = indexRightImage;
217  break;
218  }
219  case IMAGE_DISPARITY: {
220  idx = indexDisparityImage;
221  break;
222  }
223  default:
224  throw std::runtime_error("Invalid ImageType for query!");
225  }
226  if (throwIfNotFound && (idx==-1)) throw std::runtime_error("ImageSet does not contain the queried ImageType");
227  return idx;
228 }
229 
230 void ImageSet::setIndexOf(ImageType what, int idx) {
231  switch(what) {
232  case IMAGE_LEFT: {
233  indexLeftImage = idx;
234  break;
235  }
236  case IMAGE_RIGHT: {
237  indexRightImage = idx;
238  break;
239  }
240  case IMAGE_DISPARITY: {
241  indexDisparityImage = idx;
242  break;
243  }
244  default:
245  std::cout << "what=" << what << std::endl;
246  throw std::runtime_error("Invalid ImageType for setIndexOf!");
247  }
248 }
249 } // namespace
250 
int getBitsPerPixel(int imageNumber) const
Returns the number of bits that are required to store one image pixel.
Definition: imageset.h:379
void writePgmFile(int imageNumber, const char *fileName) const
Writes one image of the set to a PGM or PPM file.
Definition: imageset.cpp:101
int getIndexOf(ImageType what, bool throwIfNotFound=false) const
Returns the index of a specific image type.
Definition: imageset.cpp:208
int getNumberOfImages() const
Returns the number of images in this set.
Definition: imageset.h:400
int getBytesPerPixel(int imageNumber) const
Returns the number of bytes that are required to store one image pixel.
Definition: imageset.h:368
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:159
ImageType
Supported image types.
Definition: imageset.h:67
ImageType getImageType(int imageNumber) const
Returns the ImageType of the specified channel.
Definition: imageset.cpp:192
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:230
Nerian Vision Technologies