1 #include <Image/ImageBlenderIncremental.hh>
3 #include <MathAlgo/SVD.hh>
4 #include <Base/Common/FileHandling.hh>
5 #include <Base/Image/ImageIO.hh>
6 #include <Utils/ThreeDOut.hh>
7 #include <Base/Image/ImageConvert.hh>
10 #include <sys/sysinfo.h>
19 ImageBlenderIncremental::ImageBlenderIncremental(
bool incremental) {
20 cylinderHeight_ = 1.0;
21 SetOuputImageSize((
unsigned int)(1200));
22 blendIncremental_ = incremental;
24 drawImageBorders_ =
false;
25 horizonAlignment_ = HORIZON_ALIGNMENT_X;
27 gaussFilter_.SetSigma(1.5);
32 void ImageBlenderIncremental::
35 if (ppOutput_!=NULL) {
38 ppOutput_ = imagegeometry.
Clone();
39 ppOutput_->
GetImageSize(outputImageWidth_, outputImageHeight_);
42 struct sysinfo mysysinfo;
45 cout<<
"output image size requested: "<<outputImageWidth_
46 <<
"X"<< outputImageHeight_<<endl;
48 cout<<
"This will require more than "
49 << outputImageWidth_ * outputImageHeight_ * 64 / 1000000
50 <<
"MB of RAM, you have "<<mysysinfo.freeram / 1000000
51 <<
"MB available..."<<endl;
53 if (outputImageWidth_ * outputImageHeight_ * 70 > mysysinfo.freeram) {
55 BIASERR(endl<<endl<<endl<<
"MEMORY SHORTAGE !!! ABORTING..."<<endl<<endl<<endl);
60 BIASASSERT(outputImageHeight_>0);
61 BIASASSERT(outputImageWidth_>0);
64 pm_.SetSinkCam(P, Depth_.
IsEmpty()?NULL:&Depth_);
65 if (plane_.NormL2()>0.1) {
66 cout<<
"mapping across plane "<<plane_<<endl;
69 if (!latestMosaicHigh_.IsEmpty()) latestMosaicHigh_.Release();
70 if (!latestMosaicLow_.IsEmpty()) latestMosaicLow_.Release();
71 latestMosaicHigh_.Init(outputImageWidth_, outputImageHeight_, 4u, ImageBase::ST_float);
72 latestMosaicHigh_.SetColorModel(ImageBase::CM_RGBA);
73 latestMosaicLow_.Init(outputImageWidth_, outputImageHeight_, 4u, ImageBase::ST_float);
74 latestMosaicLow_.SetColorModel(ImageBase::CM_RGBA);
78 FillBGImage_(latestMosaicHigh_,bgcolor);
79 FillBGImage_(latestMosaicLow_,bgcolor);
86 void ImageBlenderIncremental::
88 const unsigned int w = BGImage.
GetWidth();
89 const unsigned int h = BGImage.
GetHeight();
91 const float R=bgcolor[0];
92 const float G=bgcolor[1];
93 const float B=bgcolor[2];
94 const float A=bgcolor[3];
98 for (
unsigned int x = 0; x < w; x++) {
99 for (
unsigned int y = 0; y < h; y++) {
111 void ImageBlenderIncremental::
113 weightimage_ = weights;
121 int ImageBlenderIncremental::
123 unsigned int weightType) {
126 BIASWARN(
"Projection is invalid! I'll ignore this image...");
132 ImageConvert::ToRGB(camera, temp);
139 for (
unsigned int y = 0; y < temp.
GetHeight(); y++) {
140 for (
unsigned int x = 0; x < temp.
GetWidth(); x++) {
149 ComputeAlphaChannelWeight_(temp2, weightType);
153 if (!blendIncremental_) {
160 inputImages_[uuid] = temp2;
161 imageIDs_.push_back(uuid);
164 pm_.SetSourceCam(camera.
GetProj());
165 if (plane_.NormL2()>0.1) {
167 pm_.SetPlane(plane_);
174 camCyl.
Init(outputImageWidth_, outputImageHeight_, 4);
176 FillBGImage_(camCyl,
RGBAuc(0,0,0,0));
180 pm_.Map(temp2, camCyl);
183 #ifdef BIAS_DEBUG_IBI
184 ImageIO::Save(
"IBI_lastin.mip", temp2);
185 ImageIO::Save(
"IBI_lastout.mip", camCyl);
189 GetLowPassAndHighPassImage_(camCyl, lowPassCam, highPassCam);
190 #ifdef BIAS_DEBUG_IBI
191 ImageIO::Save(
"IBI_lastlowpass.mip", lowPassCam);
192 ImageIO::Save(
"IBI_lasthighpass.mip", highPassCam);
194 LowPassFusiondAndHighPassMax_(latestMosaicLow_, latestMosaicHigh_,
195 lowPassCam, highPassCam);
196 #ifdef BIAS_DEBUG_IBI
197 ImageIO::Save(
"IBI_lasthighpass_fused.mip", latestMosaicHigh_);
198 ImageIO::Save(
"IBI_lastlowpass_fused.mip", latestMosaicLow_);
206 void ImageBlenderIncremental::
209 if (mosaic.
GetWidth()!=latestMosaicHigh_.GetWidth() ||
210 mosaic.
GetHeight()!=latestMosaicHigh_.GetHeight() ||
216 mosaic.
Init(latestMosaicHigh_.GetWidth(), latestMosaicHigh_.GetHeight(), 4);
220 AddLowPassAndHighPassImage_(latestMosaicLow_, latestMosaicHigh_,
224 void ImageBlenderIncremental::
227 if (mosaic.
GetWidth()!=latestMosaicHigh_.GetWidth() ||
228 mosaic.
GetHeight()!=latestMosaicHigh_.GetHeight() ||
234 mosaic.
Init(latestMosaicHigh_.GetWidth(), latestMosaicHigh_.GetHeight(), 3);
238 AddLowPassAndHighPassImage_(latestMosaicLow_, latestMosaicHigh_,
242 void ImageBlenderIncremental::
245 if (mosaic.
GetWidth()!=latestMosaicHigh_.GetWidth() ||
246 mosaic.
GetHeight()!=latestMosaicHigh_.GetHeight() ||
252 mosaic.
Init(latestMosaicHigh_.GetWidth(), latestMosaicHigh_.GetHeight(), 4);
256 AddLowPassAndHighPassImage_(latestMosaicLow_, latestMosaicHigh_,
260 void ImageBlenderIncremental::
263 if (mosaic.
GetWidth()!=latestMosaicHigh_.GetWidth() ||
264 mosaic.
GetHeight()!=latestMosaicHigh_.GetHeight() ||
270 mosaic.
Init(latestMosaicHigh_.GetWidth(), latestMosaicHigh_.GetHeight(), 3);
274 AddLowPassAndHighPassImage_(latestMosaicLow_, latestMosaicHigh_,
280 void ImageBlenderIncremental::
285 for (
unsigned int y = 0; y < camCyl.
GetHeight(); y++) {
286 for (
unsigned int x = 0; x < camCyl.
GetWidth(); x++) {
294 void ImageBlenderIncremental::
300 gaussFilter_.Filter7x7RGBA(camCyl, lowPassCam);
303 CopyAlphaChannel_(camCyl,lowPassCam);
305 if (DebugLevelIsSet(D_IMAGEBLENDER_FILTERING)) {
306 #ifdef BLENDER_FIX_ME
309 ImageConvert::ConvertST(dynamic_cast<const BIAS::ImageBase>(lowPassCam),
310 dynamic_cast<const BIAS::ImageBase>(temp),
314 s <<
"100_low-pass_image_" << i;
315 cout <<
"writing " << s.str() <<
" to disk..." << endl;
318 ImageIO::Save(s.str(), temp);
323 BIASCDOUT((D_IMAGEBLENDER_MINIMAL | D_IMAGEBLENDER_FILTERING),
324 "high-pass filtering... "<< endl << flush);
335 for (
unsigned int y = 0; y < highPassCam.
GetHeight(); y++) {
336 for (
unsigned int x = 0; x < highPassCam.
GetWidth(); x++) {
337 *pDH++ = *pDC++ - *pDL++;
338 *pDH++ = *pDC++ - *pDL++;
339 *pDH++ = *pDC++ - *pDL++;
347 void ImageBlenderIncremental::
357 float w, wLow, weightsum;
366 for (
unsigned int i = 0;
371 if ((i % 3000) == 0) {
372 BIASCDOUT((D_IMAGEBLENDER_MINIMAL | D_IMAGEBLENDER_BLENDING),
".");
377 weightsum = w + wLow;
379 *pDLow = (w * *pDLow + wLow * *pL++) / weightsum;
381 *pDLow = (w * *pDLow + wLow * *pL++) / weightsum;
383 *pDLow = (w * *pDLow + wLow * *pL++) / weightsum;
385 *pDLow++ = weightsum;
389 if (pH[3] > pDHigh[3]) {
407 void ImageBlenderIncremental::
415 if (channelcount==4) {
417 for (
unsigned int i = 0;
422 float sumR = pDLow[i + 0] + pDHigh[i + 0];
423 float sumG = pDLow[i + 1] + pDHigh[i + 1];
424 float sumB = pDLow[i + 2] + pDHigh[i + 2];
425 if (sumR > 255.0) sumR = 255.0;
426 if (sumG > 255.0) sumG = 255.0;
427 if (sumB > 255.0) sumB = 255.0;
428 if (sumR < 0.0) sumR = 0.0;
429 if (sumG < 0.0) sumG = 0.0;
430 if (sumB < 0.0) sumB = 0.0;
433 pDest[i + 0] = (
unsigned char)(sumR);
434 pDest[i + 1] = (
unsigned char)(sumG);
435 pDest[i + 2] = (
unsigned char)(sumB);
436 pDest[i + 3] = ALPHA_OPAQUE;
439 #ifdef BIAS_DEBUG_IBI
440 ImageIO::Save(
"IBI_last4channellow.mip", destLow);
441 ImageIO::Save(
"IBI_last4channelhigh.mip", destHigh);
442 ImageIO::Save(
"IBI_last4channelsum.mip", destination);
445 BIASASSERT(channelcount==3);
447 for (
unsigned int i = 0;
452 float sumR = *pDLow++ + *pDHigh++;
453 float sumG = *pDLow++ + *pDHigh++;
454 float sumB = *pDLow++ + *pDHigh++;
457 if (sumR > 255.0) sumR = 255.0;
458 if (sumR < 0.0) sumR = 0.0;
460 if (sumG > 255.0) sumG = 255.0;
461 if (sumG < 0.0) sumG = 0.0;
463 if (sumB > 255.0) sumB = 255.0;
464 if (sumB < 0.0) sumB = 0.0;
467 *pDest++ = (
unsigned char)(rint(sumR));
468 *pDest++ = (
unsigned char)(rint(sumG));
469 *pDest++ = (
unsigned char)(rint(sumB));
477 #ifdef BIAS_DEBUG_IBI
478 ImageIO::Save(
"IBI_last3channellow.mip", destLow);
479 ImageIO::Save(
"IBI_last3channelhigh.mip", destHigh);
480 ImageIO::Save(
"IBI_last3channelsum.mip", destination);
485 void ImageBlenderIncremental::
493 if (channelcount==4) {
495 for (
unsigned int i = 0;
498 *pDest++ = *pDLow++ + *pDHigh++;
499 *pDest++ = *pDLow++ + *pDHigh++;
500 *pDest++ = *pDLow++ + *pDHigh++;
501 *pDest++ = ALPHA_OPAQUE;
505 #ifdef BIAS_DEBUG_IBI
506 ImageIO::Save(
"IBI_last4channellow.mip", destLow);
507 ImageIO::Save(
"IBI_last4channelhigh.mip", destHigh);
508 ImageIO::Save(
"IBI_last4channelsum.mip", destination);
511 BIASASSERT(channelcount==3);
513 for (
unsigned int i = 0;
516 *pDest++ = *pDLow++ + *pDHigh++;
517 *pDest++ = *pDLow++ + *pDHigh++;
518 *pDest++ = *pDLow++ + *pDHigh++;
521 #ifdef BIAS_DEBUG_IBI
522 ImageIO::Save(
"IBI_last3channellow.mip", destLow);
523 ImageIO::Save(
"IBI_last3channelhigh.mip", destHigh);
524 ImageIO::Save(
"IBI_last3channelsum.mip", destination);
534 bool ImageBlenderIncremental::
539 if (this->blendIncremental_) {
540 BIASERR(
"Call GetMosaic() to get the result image.");
543 if (imageIDs_.size() < 1) {
544 BIASWARN(
"I need at least one image to blend!");
552 pm_.SetSinkCam(TargetProjection, Depth_.
IsEmpty()? NULL : &Depth_);
557 double superSampling = 1.0;
566 cout <<
"size of final image is "
567 << outputImageWidth_ <<
"x" << outputImageHeight_ << endl;
569 destination.
Init(outputImageWidth_, outputImageHeight_, 4);
576 BIASCDOUT((D_IMAGEBLENDER_MINIMAL | D_IMAGEBLENDER_FILTERING),
577 "filtering images..." << endl << flush);
579 gaussFilter_.SetSigma(gaussSigma);
582 for (
unsigned int i = 0; i < imageIDs_.size(); i++) {
583 BIASCDOUT((D_IMAGEBLENDER_MINIMAL | D_IMAGEBLENDER_FILTERING),
584 "processing image " << i << endl << flush);
586 Projection proj(inputImages_[imageIDs_[i]].GetProj());
589 pm_.SetSourceCam(proj);
593 camCyl.
Init(outputImageWidth_, outputImageHeight_, 4);
594 FillBGImage_(camCyl,
RGBAuc(0,0,0,0));
597 pm_.Map(inputImages_[imageIDs_[i]], camCyl,
598 mappingQuality,
false, superSampling);
601 BIASCDOUT((D_IMAGEBLENDER_MINIMAL | D_IMAGEBLENDER_FILTERING),
602 "low-pass filtering with sigma=" << gaussSigma <<
"..."
604 GetLowPassAndHighPassImage_(camCyl, lowPassCam, highPassCam);
607 BIASCDOUT(D_IMAGEBLENDER_FILTERING,
608 "writing temp low-pass image to disk... " << endl << flush);
612 ImageIO::Save(
string(
"tmp_pano_blender_low-pass_")
613 + FileHandling::toString(i)
618 BIASCDOUT(D_IMAGEBLENDER_FILTERING,
619 "writing temp high-pass image to disk... "<< endl << flush);
623 ImageIO::Save(
string(
"tmp_pano_blender_high-pass_")
624 + FileHandling::toString(i)
628 if (DebugLevelIsSet(D_IMAGEBLENDER_FILTERING)) {
629 #ifdef BLENDER_FIX_ME
632 ImageConvert::ConvertST(highPassCam, temp, ImageBase::CM_RGBA);
635 s <<
"100_high-pass_image_" << i;
636 cout <<
"writing " << s.str() <<
" to disk..." << endl;
639 ImageIO::Save(s.str(), temp);
645 if (!drawImageBorders_) {
646 inputImages_.clear();
650 BIASCDOUT((D_IMAGEBLENDER_MINIMAL | D_IMAGEBLENDER_BLENDING),
651 endl <<
"blending images");
667 for (
unsigned int imageCount = 0; imageCount < imageIDs_.size(); imageCount++) {
670 ImageIO::Load(
string(
"tmp_pano_blender_low-pass_") + FileHandling::toString(imageCount)
671 +
".mip", lowPassCam);
672 ImageIO::Load(
string(
"tmp_pano_blender_high-pass_") + FileHandling::toString(imageCount)
673 +
".mip", highPassCam);
675 LowPassFusiondAndHighPassMax_(destLow, destHigh, lowPassCam, highPassCam);
680 destination.
Clear(0);
681 AddLowPassAndHighPassImage_(destLow, destHigh, destination);
684 BIASCDOUT((D_IMAGEBLENDER_MINIMAL | D_IMAGEBLENDER_BLENDING),
688 if (drawImageBorders_) {
689 for (
unsigned int i = 0; i < imageIDs_.size(); i++) {
690 cout <<
"drawing border of image " << i << endl;
695 projection = inputImages_[imageIDs_[i]].GetProj();
716 (
unsigned int)(p2DHom[0]),
717 (
unsigned int)(p2DHom[1]),
720 (
unsigned int)(p2DHom[0]),
721 (
unsigned int)(p2DHom[1]),
724 (
unsigned int)(p2DHom[0]),
725 (
unsigned int)(p2DHom[1]),
730 (
unsigned int)(p2DHom[0]),
731 (
unsigned int)(p2DHom[1]),
746 ImageConvert::Convert(destination, rgbim, ImageBase::CM_RGB);
756 scene3D.
VRMLOut(
"cylindricPanorama.wrl");
763 void ImageBlenderIncremental::
766 if (imageIDs_.size() < 1) {
767 BIASWARN(
"I need at least one image to compute destination geometry!");
773 RMatrix RTarget(inputImages_[imageIDs_[0]].GetProj().GetR());
782 unsigned int testAlignment = horizonAlignment_;
783 if (horizonAlignment_== HORIZON_ALIGNMENT_AUTO)
786 double bestResiduum = HUGE_VAL;
787 int selectedmode = -1;
791 if (testAlignment == HORIZON_ALIGNMENT_X) {
792 for (
unsigned int i = 0; i < imageIDs_.size(); i++) {
793 RMatrix R = inputImages_[imageIDs_[i]].GetProj().GetR();
794 for (
unsigned int c=0;c<3;c++) M[i][c] = R[c][0];
796 }
else if (testAlignment == HORIZON_ALIGNMENT_Y) {
797 for (
unsigned int i = 0; i < imageIDs_.size(); i++) {
798 RMatrix R = inputImages_[imageIDs_[i]].GetProj().GetR();
799 for (
unsigned int c=0;c<3;c++) M[i][c] = R[c][1];
801 }
else if (testAlignment == HORIZON_ALIGNMENT_UNKNOWN) {
803 for (
unsigned int i = 0; i < imageIDs_.size(); i++) {
804 RMatrix R = inputImages_[imageIDs_[i]].GetProj().GetR();
805 for (
unsigned int c=0;c<3;c++) M[i][c] = R[c][2];
811 SVD svd(M, 0.1,
false);
819 for (
unsigned int i = 0; i < 3; i++) {
821 secondh[i] =vt[vt.
num_rows() - 2][i];
831 double residuum = (M*h).NormL2()/double(h.
Size());
832 double secondresiduum = (M*secondh).NormL2()/double(h.
Size());
833 double thirdresiduum = (M*thirdh).NormL2()/double(h.
Size());
835 if (residuum<1e-10) residuum = 1e-10;
836 if (secondresiduum<1e-10) secondresiduum=1e-10;
837 if (thirdresiduum<1e-10) thirdresiduum=1e-10;
844 bool nullspacedim2 = thirdresiduum / secondresiduum > 10.0;
848 if (residuum<bestResiduum && !nullspacedim2) {
851 bestResiduum = residuum;
852 selectedmode = testAlignment;
855 if (horizonAlignment_== HORIZON_ALIGNMENT_AUTO) testAlignment++;
856 }
while (testAlignment!=horizonAlignment_);
858 if (horizonAlignment_ == HORIZON_ALIGNMENT_AUTO)
switch (selectedmode) {
859 case HORIZON_ALIGNMENT_X:cout<<
"Applying horizontal alignment"<<endl;
break;
860 case HORIZON_ALIGNMENT_Y:cout<<
"Applying vertical alignment"<<endl;
break;
861 default:cout<<
"Applying optical axis alignment"<<endl;
break;
864 horizonAlignment_ = selectedmode;
869 vector< Vector3<double> > projectedVectors;
871 for (
unsigned int imCount = 0; imCount < imageIDs_.size(); imCount++) {
873 RMatrix Rot = inputImages_[imageIDs_[imCount]].GetProj().GetR();
879 if (horizonAlignment_ == HORIZON_ALIGNMENT_X) {
884 else if (horizonAlignment_ == HORIZON_ALIGNMENT_Y) {
896 orig.
Sub(temp, proj);
898 projectedVectors.push_back(proj);
903 BIASASSERT(!projectedVectors.empty());
919 vector< Vector2<double> > vectorsInPlaneSpace(projectedVectors.size());
922 planeTransform[0][0] = a[0];
923 planeTransform[0][1] = a[1];
924 planeTransform[0][2] = a[2];
925 planeTransform[1][0] = v[0];
926 planeTransform[1][1] = v[1];
927 planeTransform[1][2] = v[2];
929 for (
unsigned int i = 0; i < projectedVectors.size(); i++) {
935 planeTransform.Mult(v1, v2);
936 vectorsInPlaneSpace[i] = v2;
939 double norm = vectorsInPlaneSpace[i].
NormL2();
940 vectorsInPlaneSpace[i] /= norm;
942 cout <<
"vec " << i <<
" " << vectorsInPlaneSpace[i]
943 <<
" norm " << vectorsInPlaneSpace[i].NormL2()<< endl;
950 vector<double> angles(vectorsInPlaneSpace.size());
952 for (
unsigned int i = 0; i < vectorsInPlaneSpace.size(); i++) {
953 angles[i] = CalcAngleToXAxis_(vectorsInPlaneSpace[i],
true);
954 cout << i <<
". angle relative to reference vector " << angles[i] << endl;
958 vector<bool> visited(vectorsInPlaneSpace.size());
959 vector<double> successiveAngles;
961 double sumAngles = 0.0;
963 for (
unsigned int i = 0; i < visited.size(); i++) {
970 for (
unsigned int i = 1; i < vectorsInPlaneSpace.size(); i++) {
971 double smallestAngle = 361;
975 for (
unsigned int j = 0; j < vectorsInPlaneSpace.size(); j++) {
976 if (!visited[j] && (angles[j] < smallestAngle)) {
977 smallestAngle = angles[j];
981 BIASASSERT(index != -1);
983 visited[index] =
true;
985 if (successiveAngles.empty()) {
986 angle = smallestAngle;
989 angle = smallestAngle - successiveAngles[successiveAngles.size() - 1];
991 successiveAngles.push_back(angle);
992 indices.push_back(index);
997 double sumAnglesRemainder = sumAngles - int(sumAngles);
998 sumAngles = int(sumAngles) % 360;
999 sumAngles += sumAnglesRemainder;
1001 cout <<
"sum of all angles is " << sumAngles << endl;
1003 BIASASSERT(sumAngles <= 360);
1006 successiveAngles.push_back(360 - sumAngles);
1007 indices.push_back(0);
1009 for (
unsigned int i = 0; i < indices.size(); i++) {
1010 cout <<
"index " << indices[i]
1011 <<
" angle " << successiveAngles[i] << endl;
1015 double biggestAngle = 0.0;
1016 int indexL = -1, indexR = -1;
1018 for (
unsigned int i = 0; i < indices.size(); i++) {
1019 if (successiveAngles[i] > biggestAngle) {
1020 biggestAngle = successiveAngles[i];
1022 indexL = indices[indices.size() - 1];
1025 indexL = indices[i - 1];
1027 indexR = indices[i];
1031 cout <<
"biggest gap is " << biggestAngle <<
" degrees between axis "
1032 << indexL <<
" and " << indexR << endl;
1036 if (biggestAngle != 180.0) {
1037 midVec = (vectorsInPlaneSpace[indexL] + vectorsInPlaneSpace[indexR]) / 2.0;
1048 cout <<
"found 180 deg gap - using rot " << rotTmp << endl;
1050 cout <<
"with vec " << vectorsInPlaneSpace[indexL] << endl;
1052 rotTmp.
Mult(vectorsInPlaneSpace[indexL], midVec);
1054 cout <<
"mid vec is " << midVec << endl;
1057 midVec /= midVec.
NormL2();
1058 cout <<
"optical axis after norm " << midVec << endl;
1063 planeTransformInv = svdInvert.
Invert(planeTransform);
1069 planeTransformInv.
Mult(v1, v2);
1072 cout <<
"final optical axis is " << a << endl;
1075 a.CrossProduct(h, v);
1079 RTarget[0][0] = h[0];
1080 RTarget[1][0] = h[1];
1081 RTarget[2][0] = h[2];
1082 RTarget[0][1] = v[0];
1083 RTarget[1][1] = v[1];
1084 RTarget[2][1] = v[2];
1085 RTarget[0][2] = a[0];
1086 RTarget[1][2] = a[1];
1087 RTarget[2][2] = a[2];
1101 inline double ImageBlenderIncremental::
1115 ret = ret * 180 / M_PI;
1126 ret = 2 * M_PI - ret;
1134 inline double ImageBlenderIncremental::
1148 ret = ret * 180 / M_PI;
1159 ret = 2 * M_PI - ret;
1167 inline void ImageBlenderIncremental::
1170 cout <<
"checking fov of cameras..." << endl;
1172 double minX=1e100, minY=1e100,
1173 maxX=-1e100, maxY=-1e100;
1176 for (
unsigned int i = 0; i < imageIDs_.size(); i++) {
1181 proj = inputImages_[imageIDs_[i]].GetProj();
1202 if (!
Equal(norm, 1.0)) {
1203 BIASERR(
"ray not unit length: " << ray);
1207 if (ray[2] < minZ) {
1221 if (x[0] < minX) minX = x[0];
1222 if (x[1] < minY) minY = x[1];
1223 if (x[0] > maxX) maxX = x[0];
1224 if (x[1] > maxY) maxY = x[1];
1233 BIASCDOUT(D_IMAGEBLENDER_GEOMETRY,
1234 "Max field of view of cam "
1235 << i <<
" is " << angle << endl << flush);
1247 inputImages_[imageIDs_[i]].SetProj(
Projection(*ppp));
1251 double halfWidth = outputImageWidth_ / 2.0;
1252 double halfHeight = outputImageHeight_ / 2.0;
1254 double xMin = -1.0 * ((halfWidth - minX) / halfWidth);
1255 double xMax = (maxX - halfWidth) / halfWidth;
1257 double phiMin = -M_PI * ((halfHeight - minY) / halfHeight);
1258 double phiMax = M_PI * ((maxY - halfHeight) / halfHeight);
1260 double factor = outputImageHeight_ / (maxY - minY);
1261 outputImageWidth_ = (
unsigned int)((maxX - minX) * factor);
1266 outputImageHeight_);
1272 inline double CalculateWeightCircular(
int dx,
1274 double distCenter) {
1275 double ret = (1.0 - sqrt(
double(dx * dx + dy * dy)) / distCenter) * 255.0;
1284 inline double CalculateWeightRectangular(
unsigned int w,
1295 bool aboveAC, aboveBD;
1296 double alphaValue = 0.0;
1307 m = double(h) / double(w);
1310 mp = double(y) / double(x);
1319 mp = double(y) / double(mx + (mx - x));
1328 if (aboveAC && aboveBD) {
1329 alphaValue = double(y) / double(my);
1331 else if (aboveAC && !aboveBD) {
1332 alphaValue = double(w - x) / double(mx);
1334 else if (!aboveAC && !aboveBD) {
1335 alphaValue = double(h - y) / double(my);
1337 else if (!aboveAC && aboveBD) {
1338 alphaValue = double(x) / double(mx);
1341 return alphaValue * 255.0;
1348 void ImageBlenderIncremental::
1350 unsigned int weightType) {
1353 ConvertImageToRGBA_(image);
1355 const unsigned int w = image.
GetWidth();
1356 const unsigned int h = image.
GetHeight();
1358 const unsigned int mx = w / 2;
1359 const unsigned int my = h / 2;
1362 const double distCenter = sqrt(
double(mx * mx + my * my));
1364 if (weightType==WEIGHT_TYPE_USERIMAGE) {
1369 float *pWeight = weightimage_.GetImageData();
1371 BIASASSERT(image.
GetWidth()==weightimage_.GetWidth());
1372 BIASASSERT(image.
GetHeight()==weightimage_.GetHeight());
1373 for (
unsigned int x = 0; x < w; x++) {
1374 for (
unsigned int y = 0; y < h; y++) {
1375 *pImage = *pWeight++;
1386 const double mixRatio = 0.5;
1387 const double gain = 1.0 / (mixRatio * (1.0 - mixRatio));
1389 for (
unsigned int x = 0; x < w; x++) {
1390 for (
unsigned int y = 0; y < h; y++) {
1392 unsigned int dx = mx - x;
1393 unsigned int dy = my - y;
1395 double alphaValue = 0.0;
1397 double rectVal, circVal;
1399 switch (weightType) {
1400 case WEIGHT_TYPE_NONE:
1401 alphaValue = ALPHA_OPAQUE;
1404 case WEIGHT_TYPE_CIRCULAR:
1405 alphaValue = CalculateWeightCircular(dx, dy, distCenter);
1408 case WEIGHT_TYPE_CIRCULAR_FIT:
1410 alphaValue = CalculateWeightCircular(dx, dy, mx);
1413 alphaValue = CalculateWeightCircular(dx, dy, my);
1417 case WEIGHT_TYPE_RECTANGULAR:
1418 alphaValue = CalculateWeightRectangular(w, h, x, y, mx, my);
1421 case WEIGHT_TYPE_MIX:
1422 rectVal = CalculateWeightRectangular(w, h, x, y, mx, my) / 255.0;
1423 circVal = CalculateWeightCircular(dx, dy, distCenter) / 255.0;
1424 alphaValue = (mixRatio * rectVal)
1425 * ((1.0 - mixRatio) * circVal)
1430 case WEIGHT_TYPE_RECT_NONLINEAR:
1431 rectVal = CalculateWeightRectangular(w, h, x, y, mx, my) / 255.0;
1432 alphaValue = rectVal * rectVal * 255.0;
1436 BIASERR(
"Unknown weight type!");
1440 if (alphaValue < 0.0) alphaValue = 0.0;
1441 if (alphaValue > 255.0) alphaValue = 255.0;
1453 void ImageBlenderIncremental::
1459 ImageConvert::Convert(image, tempImage, ImageBase::CM_RGB);
1469 alphaImage.SetColorModel(ImageBase::CM_RGBA);
1470 for (
unsigned int y = 0; y < alphaImage.GetHeight(); y++) {
1471 for (
unsigned int x = 0; x < alphaImage.GetWidth(); x++) {
1473 float *pDA = &alphaImage.GetImageDataArray()[y][4 * x];
1477 *pDA++ = ALPHA_OPAQUE;
void Release()
reimplemented from ImageBase
InterpolationMethod
accuracy for resampling
unsigned int AddTriangleMesh(const TriangleMesh &mesh, const std::string &name="", const std::string &textureOutputName="", bool writeOutTexture=true, bool calcNormals=false)
Adds triangle mesh as IndexedFaceSet to ThreeDOut mem.
class HomgPoint2D describes a point with 2 degrees of freedom in projective coordinates.
computes and holds the singular value decomposition of a rectangular (not necessarily quadratic) Matr...
int VRMLOut(const std::string &sFilename)
flush all 3d objects to a vrml file with name sFilename, this is the function most users would call ...
void GenerateTexturedCamera(const ProjectionParametersBase *PPB, Image< unsigned char > &rgbtexture, const double &scale=1.0, const double &opacity=1.0, const double &resolution=1.0)
generates the sensor plane / cylinder / sphere in 3D space
void ScalarProduct(const Vector2< T > &argvec, T &result) const
scalar product of two vectors, storing the result in result
virtual void SetR(const BIAS::RMatrix &R)
Set orientation from rotation matrix R.
bool IsEmpty() const
check if ImageData_ points to allocated image buffer or not
double NormL2() const
Return the L2 norm: sqrt(a^1 + a^2 + ...)
camera parameters which define the mapping between rays in the camera coordinate system and pixels in...
void ScalarProduct(const Vector3< T > &argvec, T &result) const
scalar product (=inner product) of two vectors, storing the result in result
virtual ProjectionParametersBase * Clone() const =0
Covariant virtual copy constructor used in BIAS::Projection.
Unified output of 3D entities via OpenGL or VRML.
void SetMinZLocal(const double &minz)
sets minimum z value of unit-ray in local CCS to be accepted as in front of camera (e...
virtual bool DoesPointProjectIntoImage(const HomgPoint3D &X, HomgPoint2D &x, bool IgnoreDistortion=false) const
Checks if 3D point projects into specified image and returns belonging 2D image point.
void Mult(const Vector2< T > &argvec, Vector2< T > &destvec) const
matrix - vector multiplicate this matrix with Vector2, storing the result in destvec calculates: dest...
unsigned int GetWidth() const
virtual void UnProjectToRay(const HomgPoint2D &pos, Vector3< double > &origin, Vector3< double > &direction, bool ignoreDistortion=false) const
Calculates the view ray, which belongs to the given position on the image plane, in global coordinate...
const BIAS::UUID & GetUID() const
returns the UUID of the image
virtual void GetFirstBorderPixel(PixelIterator &it)
call this to start a run at the outer boundary of an image.
void CrossProduct(const Vector3< T > &argvec, Vector3< T > &destvec) const
cross product of two vectors destvec = this x argvec
void Clear(const StorageType value=0)
sets all pixels to zero/value
const ProjectionParametersBase * GetParameters(unsigned int cam=0) const
const parameter access function
const unsigned int Size() const
This class hides the underlying projection model, like projection matrix, spherical camera...
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
Create and represent a 3D triangle mesh.
const Matrix< double > & GetVT() const
return VT (=transposed(V))
int SetProj(const Projection &Proj)
void Mult(const T &scalar, Vector3< T > &dest) const
unsigned int GetHeight() const
class HomgPoint3D describes a point with 3 degrees of freedom in projective coordinates.
void SetPixel(const StorageType &value, const unsigned int &x, const unsigned int &y, const unsigned short int channel=0)
Set the value of a given pixel (x,y) in channel to value.
Can be used to run along the image border.
virtual int GetImageSize(unsigned int &Width, unsigned int &Height) const
Obtain image dimensions.
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
bool Equal(const T left, const T right, const T eps)
comparison function for floating point values See http://www.boost.org/libs/test/doc/components/test_...
const StorageType * GetImageData() const
overloaded GetImageData() from ImageBase
void SetUID(const BIAS::UUID &id)
void Sub(const T &scalar, Vector3< T > &dest) const
Substraction with a scalar, storing results in destination vector.
void Mult(const Matrix< T > &arg, Matrix< T > &result) const
matrix multiplication, result is not allocated
enum EColorModel GetColorModel() const
double x
If using BorderPixel methods these are the coordinates of the pixel.
int UpdateMetaData()
copy P_ and co.
Camera parameters which define the mapping between rays in the camera coordinate system and pixels in...
bool IsEmpty() const
Determine whether the Projection is Empty.
double NormL2() const
Return the L2 norm: sqrt(a^2 + b^2)
Matrix< double > Invert()
returns pseudoinverse of A = U * S * V^T A^+ = V * S^+ * U^T
Subscript num_rows() const
virtual void UnProjectLocal(const HomgPoint2D &pos, Vector3< double > &pointOnRay, Vector3< double > &direction, bool IgnoreDistortion=false) const
calculates the viewing ray from the camera center (in the camera coordinate system) which belongs to ...
interface class for producing/storing Universally Unique IDentifiers
Camera parameters which define the mapping between rays in the camera coordinate system and pixels in...
const BIAS::Projection & GetProj() const
virtual void SetC(const BIAS::Vector3< double > &C)
Set projection center.
Vector3< T > & Normalize()
normalize this vector to length 1
void SetZero()
zeroes the image
double NormL2() const
the L2 norm sqrt(a^2 + b^2 + c^2)
bool IsValid() const
checks whether this uuid is valid(true) or unitialized(false)
virtual bool GetNextBorderPixel(PixelIterator &it)
call this iteratively to run at the outer boundary of an image.
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase