SLProject  4.3.020
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
SENSUtils.cpp
Go to the documentation of this file.
1 #include "SENSUtils.h"
2 #include <Utils.h>
3 
4 namespace SENS
5 {
6 //https://www.khronos.org/opengl/wiki/Common_Mistakes section Texture upload and pixel reads:
7 //If pixel format is rgb or bgr (only 3 layers), we have to make sure that the (width * 3 bytes) is devidable by 4
8 //For rgba images the problem cannot arise. By the way, the GPU will most likely convert the rgb to rbga anyway.
9 bool calcCrop(cv::Size inputSize, float targetWdivH, int& cropW, int& cropH, int& width, int& height)
10 {
11  cropH = 0; // crop height in pixels of the source image
12  cropW = 0; // crop width in pixels of the source image
13  width = inputSize.width; // width in pixels of the destination image
14  height = inputSize.height; // height in pixels of the destination image
15 
16  float inWdivH = (float)inputSize.width / (float)inputSize.height;
17  // viewportWdivH is negative the viewport aspect will be the same
18  float outWdivH = targetWdivH < 0.0f ? inWdivH : targetWdivH;
19  if (Utils::abs(inWdivH - outWdivH) > 0.01f)
20  {
21  int wModulo4;
22  int hModulo4;
23 
24  if (inWdivH > outWdivH) // crop input image left & right
25  {
26  width = (int)((float)inputSize.height * outWdivH);
27  height = inputSize.height;
28  cropW = (int)((float)(inputSize.width - width) * 0.5f);
29 
30  // Width must be devidable by 4
31  wModulo4 = width % 4;
32  if (wModulo4 == 1) width--;
33  if (wModulo4 == 2)
34  {
35  cropW++;
36  width -= 2;
37  }
38  if (wModulo4 == 3) width++;
39  }
40  else // crop input image at top & bottom
41  {
42  width = inputSize.width;
43  height = (int)((float)inputSize.width / outWdivH);
44  cropH = (int)((float)(inputSize.height - height) * 0.5f);
45 
46  // Height must be devidable by 4
47  hModulo4 = height % 4;
48  if (hModulo4 == 1) height--;
49  if (hModulo4 == 2)
50  {
51  cropH++;
52  height -= 2;
53  }
54  if (hModulo4 == 3) height++;
55  }
56  return true;
57  }
58  else
59  return false;
60 }
61 
62 void cropImage(cv::Mat& img, float targetWdivH, int& cropW, int& cropH)
63 {
64  int width, height;
65  if (calcCrop(img.size(), targetWdivH, cropW, cropH, width, height))
66  {
67  //imwrite("cropImageToImgBefore.bmp", img);
68  img = img(cv::Rect(cropW, cropH, width, height));
69  //imwrite("cropImageToImgAfter.bmp", img);
70  }
71 }
72 
73 void cropImageTo(const cv::Mat& img, cv::Mat& outImg, float targetWdivH, int& cropW, int& cropH)
74 {
75  int width, height;
76  if (calcCrop(img.size(), targetWdivH, cropW, cropH, width, height))
77  {
78  img(cv::Rect(cropW, cropH, width, height)).copyTo(outImg);
79  //imwrite("cropImageToImg.bmp", img);
80  //imwrite("cropImageToOutImg.bmp", outImg);
81  }
82 }
83 
84 //opposite to crop image: extend
85 void extendWithBars(cv::Mat& img, float targetWdivH)
86 {
87  //HighResTimer t;
88  float inWdivH = (float)img.cols / (float)img.rows;
89  float outWdivH = targetWdivH < 0.0f ? inWdivH : targetWdivH;
90 
91  int addT = 0, addB = 0, addL = 0, addR = 0;
92  if (Utils::abs(inWdivH - outWdivH) > 0.01f)
93  {
94  int width = 0; // width in pixels of the destination image
95  int height = 0; // height in pixels of the destination image
96 
97  if (inWdivH > outWdivH) // add bar bottom and top (old: crop input image left & right)
98  {
99  width = img.cols;
100  height = (int)((float)img.cols / outWdivH);
101  addT = (int)((float)(height - img.rows) * 0.5f);
102  addB = height - addT - img.rows;
103  }
104  else // add bar left and right (old: crop input image at top & bottom)
105  {
106  width = (int)((float)img.rows * outWdivH);
107  height = img.rows;
108 
109  // Width in bytes must be devidable by 4:
110  //(e.g. for RGBA images this is already true. For RGB images we have to check if (width * 3bytes) is dividable by 4)
111  if (img.channels() != 4)
112  {
113  //we make this problem more easy: if width is dividable by 4 then n*width is also dividable by four
114  int wModulo4 = width % 4;
115  //we alway fill up, becaus we have to add pixels anyway
116  width += (4 - wModulo4);
117  }
118  addL = (int)((float)(width - img.cols) * 0.5f);
119  addR = width - addL - img.cols;
120  }
121 
122  /*
123  if (cvBorderType == cv::BORDER_REPLICATE)
124  {
125  //Camera image on mobile devices have wrongly colored pixels on the right. We want to correct this
126  //by cutting away some pixels from the right border in case of BORDER_REPLICATE
127  int numCorrPixRight = 2;
128  cv::Rect roi(0, 0, img.size().width - numCorrPixRight, img.size().height);
129  cv::Mat img2 = img(roi);
130  int addLeft = addW;
131  int addRight = addW + numCorrPixRight;
132  cv::Scalar value(0, 0, 0);
133  //BORDER_ISOLATED enables to respect the adjusted roi
134  copyMakeBorder(img2, img, addH, addH, addLeft, addRight, cvBorderType | cv::BORDER_ISOLATED, value);
135 
136  //Utils::log("extendWithBars", "elapsed time without smooth %f ms", t.elapsedTimeInMilliSec());
137 
138  if (addH > 0)
139  {
140  Utils::log("extendWithBars", "addW blurring not implemented yet!!");
141  }
142  else if (addW > 0)
143  {
144  //not working on ios with new ipad for 640x480
145  cv::Size iS = img.size();
146  //left
147  cv::Rect barRoiL(0, 0, addLeft, iS.height);
148  cv::Mat barImgL = img(barRoiL);
149  cv::blur(barImgL, barImgL, cv::Size(1, 5), cv::Point(-1, -1));
150  //right
151  cv::Rect barRoiR(iS.width - addRight, 0, addRight, iS.height);
152  cv::Mat barImgR = img(barRoiR);
153  cv::blur(barImgR, barImgR, cv::Size(1, 5), cv::Point(-1, -1));
154  }
155  }
156  else
157  {
158 
159  }
160  */
161 
162  cv::Scalar value(0, 0, 0);
163  copyMakeBorder(img, img, addT, addB, addL, addR, cv::BORDER_CONSTANT, value);
164 
165  assert((img.size().width * img.channels()) % 4 == 0);
166  }
167  //Utils::log("extendWithBars", "elapsed time total %f ms", t.elapsedTimeInMilliSec());
168 }
169 
170 void mirrorImage(cv::Mat& img, bool mirrorH, bool mirrorV)
171 {
172  if (mirrorH)
173  {
174  cv::Mat mirrored;
175  if (mirrorV)
176  cv::flip(img, mirrored, -1);
177  else
178  cv::flip(img, mirrored, 1);
179  img = mirrored;
180  }
181  else if (mirrorV)
182  {
183  cv::Mat mirrored;
184  if (mirrorH)
185  cv::flip(img, mirrored, -1);
186  else
187  cv::flip(img, mirrored, 0);
188  img = mirrored;
189  }
190 }
191 
192 float calcFOVDegFromFocalLengthPix(const float focalLengthPix, const int imgLength)
193 {
194  float fovRad = 2.f * atanf(0.5f * (float)imgLength / focalLengthPix);
195  float fovDeg = fovRad * (float)SENS_RAD2DEG;
196  return fovDeg;
197 }
198 
199 float calcFocalLengthPixFromFOVDeg(const float fovDeg, const int imgLength)
200 {
201  float fovRad = fovDeg * (float)SENS_DEG2RAD;
202  float focalLengthPix = 0.5f * imgLength / tanf(0.5f * fovRad);
203  return focalLengthPix;
204 }
205 
206 float calcFovDegFromOtherFovDeg(const float otherFovDeg, const int otherLength, const int length)
207 {
208  float f = (0.5f * (float)otherLength) / tanf(otherFovDeg * 0.5f * (float)SENS_DEG2RAD);
209  return 2.f * atan(0.5f * (float)length / f) * (float)SENS_RAD2DEG;
210 }
211 
212 cv::Mat adaptCameraMat(cv::Mat origMat, int newRefLength, int oldRefLength)
213 {
214  double scale = (double)newRefLength / (double)oldRefLength;
215  cv::Mat newMat(3, 3, CV_64F);
216  newMat.at<double>(0, 0) = scale * origMat.at<double>(0, 0); //fx
217  newMat.at<double>(0, 1) = 0.0;
218  newMat.at<double>(0, 2) = scale * origMat.at<double>(0, 2); //cx
219  newMat.at<double>(1, 0) = 0.0;
220  newMat.at<double>(1, 1) = scale * origMat.at<double>(1, 1); //fy
221  newMat.at<double>(1, 2) = scale * origMat.at<double>(1, 2); //cy
222  newMat.at<double>(2, 0) = 0.0;
223  newMat.at<double>(2, 1) = 0.0;
224  newMat.at<double>(2, 2) = 1.0;
225 
226  return newMat;
227 }
228 
229 /*
230 float calcFovOfCenteredImg(const float oldFovDeg, const int oldImgLength, const int newImgLength)
231 {
232  float oldFovRadHalf = SENS_DEG2RAD * 0.5f * oldFovDeg;
233  float newFovDeg = SENS_RAD2DEG * 2 * atan( (float)newImgLength / (float)oldImgLength * tan(oldFovRadHalf));
234  return newFovDeg;
235 }
236 */
237 
238 };
#define SENS_DEG2RAD
Definition: SENSUtils.h:7
#define SENS_RAD2DEG
Definition: SENSUtils.h:8
void extendWithBars(cv::Mat &img, float targetWdivH)
Definition: SENSUtils.cpp:85
void mirrorImage(cv::Mat &img, bool mirrorH, bool mirrorV)
Definition: SENSUtils.cpp:170
float calcFocalLengthPixFromFOVDeg(const float fovDeg, const int imgLength)
Definition: SENSUtils.cpp:199
float calcFOVDegFromFocalLengthPix(const float focalLengthPix, const int imgLength)
Definition: SENSUtils.cpp:192
void cropImageTo(const cv::Mat &img, cv::Mat &outImg, float targetWdivH, int &cropW, int &cropH)
Definition: SENSUtils.cpp:73
void cropImage(cv::Mat &img, float targetWdivH, int &cropW, int &cropH)
Definition: SENSUtils.cpp:62
bool calcCrop(cv::Size inputSize, float targetWdivH, int &cropW, int &cropH, int &width, int &height)
Definition: SENSUtils.cpp:9
cv::Mat adaptCameraMat(cv::Mat origMat, int newRefLength, int oldRefLength)
Definition: SENSUtils.cpp:212
float calcFovDegFromOtherFovDeg(const float otherFovDeg, const int otherLength, const int length)
Definition: SENSUtils.cpp:206
T abs(T a)
Definition: Utils.h:249