475 const std::vector<std::string>& objectClassNames,
481 if (objectClassNames.size() < 1)
483 ARMARX_WARNING <<
"objectClassNames.size() = " << objectClassNames.size()
484 <<
", something is wrong here! ";
486 memoryx::ObjectLocalizationResultList resultList;
492 contextGL->MakeCurrent();
494 Object3DList objectList;
496 for (std::string
const& className : objectClassNames)
498 Object3DList classObjectList;
500 int dilationCount = 2;
502 auto classEntryIter = database.find(className);
503 if (classEntryIter == database.end())
505 ARMARX_WARNING <<
"Could not find database entry for: " << className;
509 ObjectColor color = classEntry.
color;
511 std::vector<HSVSegmentationParams> hsvSegmentationParams;
513 if (color == eYellow3)
515 hsvSegmentationParams.push_back(getSegmentationParamsFromColor(colorParameters, eRed));
516 hsvSegmentationParams.push_back(
517 getSegmentationParamsFromColor(colorParameters, eYellow));
518 hsvSegmentationParams.back().minRatio = 0.2f;
522 HSVSegmentationParams hsvSegmentationParam =
523 getSegmentationParamsFromColor(colorParameters, color);
524 hsvSegmentationParams.push_back(hsvSegmentationParam);
530 int width = leftInput->width;
531 int height = leftInput->height;
534 CByteImage grayImageBig(width, height, CByteImage::eGrayScale);
535 ::ImageProcessor::ConvertImage(leftInput, &grayImageBig,
true);
537 BlobDetector leftBlobDetector(width, height);
538 BlobDetector rightBlobDetector(width, height);
540 Object2DList leftObjects = leftBlobDetector.findColoredRegions(
541 leftInput, paramMinPixelsPerRegion, hsvSegmentationParams, dilationCount);
542 Object2DList rightObjects = rightBlobDetector.findColoredRegions(
543 rightInput, paramMinPixelsPerRegion, hsvSegmentationParams, dilationCount);
545 for (Object2DEntry
const& entry : leftObjects)
547 ::PrimitivesDrawer::DrawRegion(
resultImages[0], entry.region, 255, 0, 0, 2);
551 Object3DList blobList;
553 float maxEpipolarDistance = this->maxEpipolarDistance;
555 bool inputImagesAreRectified =
false;
557 float minZDistance = 500;
558 float maxZDistance = 3000;
560 for (Object2DEntry& leftObject : leftObjects)
562 Object2DEntry
const* bestMatch =
nullptr;
563 float bestDiff = maxEpipolarDistance;
564 for (Object2DEntry& rightObject : rightObjects)
567 leftObject.region.nPixels < rightObject.region.nPixels
568 ? (
float)leftObject.region.nPixels / rightObject.region.nPixels
569 : (
float)rightObject.region.nPixels / leftObject.region.nPixels;
570 float aspectRatioRatio =
571 leftObject.region.ratio < rightObject.region.ratio
572 ? (
float)leftObject.region.ratio / rightObject.region.ratio
573 : (
float)rightObject.region.ratio / leftObject.region.ratio;
575 Vec2d leftCentroid = leftObject.region.centroid;
576 Vec2d rightCentroid = rightObject.region.centroid;
579 if (inputImagesAreRectified)
581 yDiff = fabsf(leftCentroid.y - rightCentroid.y);
585 yDiff = stereoCalibration->CalculateEpipolarLineInLeftImageDistance(
586 leftCentroid, rightCentroid);
591 stereoCalibration->Calculate3DPoint(leftCentroid,
594 inputImagesAreRectified,
595 useDistortionParameters);
598 if (pixelRatio > 0.5f && aspectRatioRatio > 0.5f &&
599 yDiff <= maxEpipolarDistance && position.z >= minZDistance &&
600 position.z <= maxZDistance && yDiff <= bestDiff)
603 bestMatch = &rightObject;
610 Object2DEntry
const& rightObject = *bestMatch;
613 entry.region_left = leftObject.region;
614 entry.region_right = rightObject.region;
615 entry.region_id_left = leftObject.id;
616 entry.region_id_right = rightObject.id;
618 stereoCalibration->Calculate3DPoint(entry.region_left.centroid,
619 entry.region_right.centroid,
620 entry.pose.translation,
621 inputImagesAreRectified,
622 useDistortionParameters);
624 entry.world_point = entry.pose.translation;
626 blobList.push_back(entry);
632 CByteImage* segmented = &leftBlobDetector.segmented;
635 const unsigned char* input = segmented->pixels;
636 unsigned char* output = resultImage->pixels;
637 int nPixels = segmented->width * segmented->height;
641 hsv2rgb(0, 255, 100, r, g, b);
643 for (
int i = 0; i < nPixels; i++)
647 const int offset = 3 * i;
648 output[offset + 0] = r;
649 output[offset + 1] = g;
650 output[offset + 2] = b;
658 CByteImage segmentedObject(width, height, CByteImage::eGrayScale);
659 ::ImageProcessor::ConvertImage(leftInput, &segmentedObject);
660 ::ImageProcessor::And(segmented, &segmentedObject, &segmentedObject);
664 for (Object3DEntry& blob : blobList)
666 const MyRegion& region = blob.region_left;
668 int length = SegmentableBitmapWidth;
669 CByteImage objectGray(length, length, CByteImage::eGrayScale);
674 CropImageToTemplate(&segmentedObject, region, &objectGray);
678 ::ImageProcessor::ThresholdBinarize(&objectGray, &objectGray, 1);
682 CByteImage* input = &objectGray;
688 for (std::uint32_t i = 0; i < templateHeader.
templateCount; ++i)
694 int stride = input->width;
696 for (
int y = 0; y < (int)SegmentableBitmapWidth; ++y)
698 std::uint32_t
const* templateRow =
template_.bitmap + y * 2;
699 unsigned char const* inputRow = input->pixels + y * stride;
700 for (
int x = 0;
x < (int)(SegmentableBitmapWidth / 32); ++
x)
702 std::uint32_t compressed = templateRow[
x];
704 for (
int i = 0; i < 32; ++i)
706 bool inputPixel = inputRow[
x * 32 + i] > 0;
707 bool templatePixel = (compressed & (1 << i)) > 0;
708 if ((inputPixel && templatePixel) ||
709 (!inputPixel && !templatePixel))
718 if (overlap > bestOverlap)
720 bestOverlap = overlap;
721 bestTemplate = &template_;
726 1.0f * bestOverlap / (SegmentableBitmapWidth * SegmentableBitmapWidth);
728 if (!bestTemplate || overlapRatio < paramTemplateMatchThreshold)
731 <<
"Could not find a matching template (overlap ratio: " << overlapRatio
738 Transformation3d& poseData = blob.pose;
746 Math3d::SetRotationMatX(poseData.rotation, convention.x);
747 Math3d::SetRotationMatZ(temp, convention.z);
748 Math3d::MulMatMat(poseData.rotation, temp, poseData.rotation);
749 Math3d::SetRotationMatY(temp, convention.y);
750 Math3d::MulMatMat(poseData.rotation, temp, poseData.rotation);
754 Vec3d position = blob.pose.translation;
755 Mat3d orientation = blob.pose.rotation;
756 Mat3d& resultOrientation = blob.pose.rotation;
758 Vec3d u0 = {0, 0, 1};
760 Math3d::NormalizeVec(u);
763 Mat3d correctiveRotation;
765 Math3d::CrossProduct(u0, u, axis);
766 float angle = Math3d::Angle(u0, u, axis);
767 Math3d::SetRotationMatAxis(correctiveRotation, axis,
angle);
770 Math3d::MulMatMat(correctiveRotation, orientation, resultOrientation);
774 orientation = resultOrientation;
775 float resultCorrelation = 0.0f;
776 float resultSizeRatio = 0.0f;
777 CByteImage* initialMask = &objectGray;
778 int nSize = region.nPixels;
779 int nSimulatedSize = 0;
781 Vec3d initialPosition = position;
787 const int width = stereoCalibration->width;
788 const int height = stereoCalibration->height;
790 Transformation3d pose;
791 Math3d::SetVec(pose.translation, position);
792 Math3d::SetMat(pose.rotation, orientation);
794 CByteImage image_left(width, height, CByteImage::eGrayScale);
795 CByteImage image_right(width, height, CByteImage::eGrayScale);
796 CByteImage* ppImages[2] = {&image_left, &image_right};
799 m_pOpenGLVisualizer->Clear();
800 m_pOpenGLVisualizer->ActivateShading(
false);
801 m_pOpenGLVisualizer->SetProjectionMatrix(
802 stereoCalibration->GetLeftCalibration());
804 CFloatMatrix* model = database[className].model.get();
805 m_pOpenGLVisualizer->DrawObject(model, pose);
806 m_pOpenGLVisualizer->GetImage(&image_left);
807 ::ImageProcessor::FlipY(&image_left, &image_left);
810 m_pOpenGLVisualizer->Clear();
811 m_pOpenGLVisualizer->SetProjectionMatrix(
812 stereoCalibration->GetRightCalibration());
814 m_pOpenGLVisualizer->DrawObject(model, pose);
815 m_pOpenGLVisualizer->GetImage(&image_right);
816 ::ImageProcessor::FlipY(&image_right, &image_right);
822 m_pObjectFinderStereo->ClearObjectList();
823 m_pObjectFinderStereo->FindObjectsInSegmentedImage(
824 ppImages, 0, eRed, 100,
false);
825 m_pObjectFinderStereo->Finalize(0, 10000,
false, eRed, 10,
false);
826 const Object3DList& objectList = m_pObjectFinderStereo->GetObject3DList();
828 if (objectList.size() == 1)
830 Object3DEntry
const& simEntry = objectList[0];
832 Vec3d positionCorrection;
833 Math3d::SubtractVecVec(
834 position, simEntry.pose.translation, positionCorrection);
835 Math3d::AddVecVec(initialPosition, positionCorrection, position);
839 nSimulatedSize = objectList.at(0).region_left.nPixels;
842 const int k = SegmentableBitmapWidth;
843 CByteImage simulatedObject(k, k, CByteImage::eGrayScale);
845 &image_left, simEntry.region_left, &simulatedObject);
848 for (std::size_t j = 0; j < SegmentableBitmapSize; j++)
850 sum +=
abs(simulatedObject.pixels[j] - initialMask->pixels[j]);
854 float divisor = 255.0f * SegmentableBitmapSize;
855 resultCorrelation = 1.0f - sum / divisor;
856 resultSizeRatio = nSimulatedSize < nSize
857 ?
float(nSimulatedSize) / nSize
858 :
float(nSize) / nSimulatedSize;
863 <<
"' in simulated image";
867 if (resultSizeRatio < paramSizeRatioThreshold)
869 ARMARX_VERBOSE <<
"Detected blob size is too different in real image "
870 "compared to simulated image ("
871 <<
"real size: " << nSize
872 <<
", simulated size: " << nSimulatedSize
873 <<
", ratio: " << resultSizeRatio <<
")";
875 else if (resultCorrelation < paramCorrelationThreshold)
878 <<
"Detected blob does not correlate with the simulated blob ("
879 <<
"ratio: " << resultCorrelation <<
")";
883 blob.sName = className;
885 blob.quality = resultSizeRatio;
886 blob.quality2 = resultCorrelation;
887 blob.localizationValid =
true;
889 ARMARX_VERBOSE <<
"Found a match (overlap ratio: " << overlapRatio
890 <<
", size ratio: " << resultSizeRatio
891 <<
", correlation: " << resultCorrelation
892 <<
", blob size: " << nSize <<
")";
894 classObjectList.push_back(blob);
898 if (classObjectList.size() > 1 && paramSingleInstance)
900 std::sort(classObjectList.begin(),
901 classObjectList.end(),
902 [](Object3DEntry
const& left, Object3DEntry
const& right)
903 { return left.quality > right.quality; });
904 Object3DEntry& bestMatch = classObjectList.front();
905 objectList.push_back(bestMatch);
909 objectList.insert(objectList.end(), classObjectList.begin(), classObjectList.end());
917 if (objectList.size() == 0)
922 for (std::string
const& className : objectClassNames)
924 CColorParameterSet::Translate(database[className].color, color);
935 memoryx::ObjectLocalizationResultList resultList;
937 for (Object3DList::iterator iter = objectList.begin(); iter != objectList.end(); iter++)
939 float x = iter->pose.translation.x;
940 float y = iter->pose.translation.y;
941 float z = iter->pose.translation.z;
943 if (seq.count(iter->sName))
949 seq[iter->sName] = 0;
954 mapValues[
"y"] =
new Variant(y);
955 mapValues[
"z"] =
new Variant(z);
956 mapValues[
"name"] =
new Variant(iter->sName);
957 mapValues[
"sequence"] =
new Variant(seq[iter->sName]);
959 debugObserver->setDebugChannel(
"ObjectRecognition", mapValues);
962 if (
x > validResultBoundingBoxMin.x && y > validResultBoundingBoxMin.y &&
963 z > validResultBoundingBoxMin.z &&
x < validResultBoundingBoxMax.x &&
964 y < validResultBoundingBoxMax.y && z < validResultBoundingBoxMax.z)
967 memoryx::ObjectLocalizationResult result;
970 Eigen::Vector3f position(
971 iter->pose.translation.x, iter->pose.translation.y, iter->pose.translation.z);
972 Eigen::Matrix3f orientation;
973 orientation << iter->pose.rotation.r1, iter->pose.rotation.r2, iter->pose.rotation.r3,
974 iter->pose.rotation.r4, iter->pose.rotation.r5, iter->pose.rotation.r6,
975 iter->pose.rotation.r7, iter->pose.rotation.r8, iter->pose.rotation.r9;
984 iter->region_right.centroid);
987 result.recognitionCertainty =
988 0.5f + 0.5f * calculateRecognitionCertainty(iter->sName, *iter);
989 result.objectClassName = iter->sName;
992 resultList.push_back(result);
996 ARMARX_VERBOSE <<
"Refused unrealistic localization at position: " <<
x <<
" " << y
1001 ARMARX_VERBOSE <<
"Finished localizing " << objectClassNames.at(0);