13 #include <vtkBalloonRepresentation.h>
14 #include <vtkBalloonWidget.h>
15 #include <vtkCellData.h>
16 #include <vtkFloatArray.h>
17 #include <vtkLookupTable.h>
18 #include <vtkPolyData.h>
19 #include <vtkPolyDataMapper.h>
20 #include <vtkProperty.h>
21 #include <vtkTransform.h>
31 #include <tbb/parallel_for.h>
44 assert(!slice.empty());
46 this->m_slice.clear();
47 this->m_slice.assign(slice.begin(), slice.end());
48 this->actor =
nullptr;
49 this->boxWidget =
nullptr;
53 : visible(visible_), lock(lock_) {
63 cubeTransform->PostMultiply();
64 cubeTransform->Scale(label.
detail.length, label.
detail.width,
67 cubeTransform->Translate(label.
detail.center_x, label.
detail.center_y,
85 this->m_slice.clear();
86 this->m_slice.assign(slice.begin(), slice.end());
94 cubeTransform->PostMultiply();
95 cubeTransform->Scale(label.
detail.length, label.
detail.width,
98 cubeTransform->Translate(label.
detail.center_x, label.
detail.center_y,
106 for (
auto p : anchorPoints) {
109 anchorPoints.clear();
116 mapper->SetInputConnection(source->GetOutputPort());
118 actor->SetMapper(mapper);
124 if (!this->actor)
return;
128 lut->SetNumberOfTableValues(2);
132 lut->SetTableValue(0, c.
r / 255.0, c.
g / 255.0, c.
b / 255.0, 0);
133 lut->SetTableValue(1, c.
r / 255.0, c.
g / 255.0, c.
b / 255.0, 1);
138 lut->SetTableValue(0, c.
r / 255.0, c.
g / 255.0, c.
b / 255.0, 0);
139 lut->SetTableValue(1, c.
r / 255.0, c.
g / 255.0, c.
b / 255.0, 1);
146 for (
int i = 0; i < 12; i++) {
147 cellData->InsertNextValue(1);
151 for (
int i = 0; i < 6; i++) {
152 cellData->InsertNextValue(0);
156 cellData->InsertValue(12, 1);
159 source->GetOutput()->GetCellData()->SetScalars(cellData);
161 actor->GetProperty()->SetLineWidth(2);
162 actor->GetProperty()->SetLighting(
false);
164 mapper->SetLookupTable(lut);
168 const std::vector<int>& slice) {
169 if (cloud->size() == 0 || slice.empty())
return;
171 int num =
static_cast<int>(slice.size());
172 anchorPoints.clear();
173 anchorPoints.resize(slice.size());
183 #pragma omp parallel
for
185 for (
int dataIndex = 0; dataIndex < num; ++dataIndex)
188 double* p =
new double[3];
189 p[0] =
static_cast<double>(
191 ->points[
static_cast<std::size_t
>(
192 slice[
static_cast<std::size_t
>(
195 p[1] =
static_cast<double>(
197 ->points[
static_cast<std::size_t
>(
198 slice[
static_cast<std::size_t
>(
201 p[2] =
static_cast<double>(
203 ->points[
static_cast<std::size_t
>(
204 slice[
static_cast<std::size_t
>(
207 anchorPoints[
static_cast<std::size_t
>(dataIndex)] = p;
222 transform->GetPosition(p);
223 transform->GetScale(s);
224 transform->GetOrientation(o);
225 memcpy(label.
data, p, 3 *
sizeof(
double));
226 memcpy(label.
data + 3, s, 3 *
sizeof(
double));
233 if (t == transform)
return;
236 actor->SetUserTransform(t);
242 if (!this->actor)
return;
248 boxWidgetCallback0->setAnno(
this);
250 boxWidgetCallback1->setAnno(
this);
252 boxWidget->SetInteractor(interactor);
260 double bounds[6] = {-1, 1, -1, 1, -1, 1};
261 boxWidget->PlaceWidget(bounds);
263 boxWidget->SetHandleSize(0.01);
264 boxWidget->GetOutlineProperty()->SetAmbientColor(1.0, 0.0, 0.0);
265 boxWidget->AddObserver(vtkCommand::InteractionEvent,
267 boxWidget->AddObserver(vtkCommand::EndInteractionEvent,
272 t->DeepCopy(actor->GetUserTransform());
273 boxWidget->SetTransform(t);
278 if (this->boxWidget) {
284 if (anchorPoints.size() == 0)
return;
286 transform->GetPosition(center);
288 double r[3],
x[3],
z[3],
y[3] = {0, 1, 0};
291 transform->GetOrientation(r);
293 z[0] = std::sin(vtkMath::RadiansFromDegrees(r[1]));
295 z[2] = std::cos(vtkMath::RadiansFromDegrees(r[1]));
300 vtkMath::MultiplyScalar(
x, scs[1]);
302 vtkMath::MultiplyScalar(
y, scs[1]);
304 vtkMath::MultiplyScalar(
z, scs[1]);
307 vtkMath::Add(center,
x, center);
308 vtkMath::Add(center,
y, center);
309 vtkMath::Add(center,
z, center);
312 t->Translate(center);
316 boxWidget->SetTransform(t);
336 vtkMath::Normalize(o);
339 a = -std::numeric_limits<double>::max();
340 b = std::numeric_limits<double>::max();
343 for (
auto x : anchorPoints) {
344 vtkMath::Subtract(
x, this->center, t);
345 double s = vtkMath::Dot(t, o);
350 scs[1] = (
a + b) / 2;
356 types =
new vector<string>();
364 for (std::size_t i = 0; i <
types->size(); i++) {
365 if (
types->at(i) == type_)
return i;
368 types->push_back(type_);
369 return types->size() - 1;
374 if (index >
types->size() - 1) {
378 return types->at(index);
382 std::vector<int>& slice,
385 p1[0] = std::numeric_limits<double>::max();
386 p1[1] = std::numeric_limits<double>::max();
387 p1[2] = std::numeric_limits<double>::max();
390 p2[0] = -std::numeric_limits<double>::max();
391 p2[1] = -std::numeric_limits<double>::max();
392 p2[2] = -std::numeric_limits<double>::max();
394 for (
auto i : slice) {
395 std::size_t index =
static_cast<std::size_t
>(i);
396 p1[0] = std::min(p1[0],
static_cast<double>(cloud->points[index].x));
397 p1[1] = std::min(p1[1],
static_cast<double>(cloud->points[index].y));
398 p1[2] = std::min(p1[2],
static_cast<double>(cloud->points[index].z));
400 p2[0] = std::max(p2[0],
static_cast<double>(cloud->points[index].x));
401 p2[1] = std::max(p2[1],
static_cast<double>(cloud->points[index].y));
402 p2[2] = std::max(p2[2],
static_cast<double>(cloud->points[index].z));
407 : m_interactor(interactor) {
411 balloonRep->SetBalloonLayoutToImageRight();
485 int num =
static_cast<int>(anno->
getSlice().size());
495 #pragma omp parallel
for
497 for (
int dataIndex = 0; dataIndex < num; ++dataIndex)
504 std::size_t
>(dataIndex)]] = 0;
507 std::size_t
>(dataIndex)]] = Annotype;
524 std::vector<size_t> indices;
531 for (i = 0; i < indices.size(); ++i) {
532 if (annotationsMap.find(indices[i]) == annotationsMap.end()) {
533 annotationsMap[indices[i]] = vector<int>();
535 annotationsMap[indices[i]].push_back(
static_cast<int>(i));
538 CVLog::Print(QString(
"loadAnnotations: finish cost %1 s")
541 CVLog::Warning(
"label files are probably corrupted and drop it!");
545 if (!annotationsMap.empty()) {
546 for (AnnotationMap::iterator iter_int = annotationsMap.begin();
547 iter_int != annotationsMap.end(); iter_int++) {
548 size_t typeIndex = iter_int->first;
550 if (
type ==
"")
continue;
551 vector<int> slice = iter_int->second;
556 }
else if (mode == 1)
558 std::ifstream input(
filename.c_str(), std::ios::in);
561 QString(
"Cannot open file : %1").arg(
filename.c_str()));
565 while (input >>
type) {
568 for (
int j = 0; j < 7; j++) {
569 input >> label.
data[j];
637 }
else if (mode == 1)
640 ss += (anno->getBoxLabel().toString() +
"\n");
644 QString(
"unknown mode: %1, only semantic and box supported!")
650 strlen(ss.c_str()))) {
671 if (anno->getActor() == actor) {
680 if (!anno->
getActor())
return index;
684 if (anno2->getActor() == anno->
getActor()) {
692 if (index >
getSize() - 1)
return nullptr;
697 std::vector<Annotation*>& annotations) {
699 if (anno2->getType() ==
type) {
700 annotations.push_back(anno2);
706 if (index >
getSize() - 1)
return;
720 if (annIndex < 0)
return;
map< size_t, std::vector< int > > AnnotationMap
Annotaions(vtkRenderWindowInteractor *interactor=nullptr)
void loadAnnotations(std::string filename, int mode)
load annotations from file
void add(Annotation *anno)
void updateBalloonByIndex(std::size_t index)
std::vector< Annotation * > m_annotations
keep all annotation from current cloud
Annotation * getAnnotation(vtkActor *actor)
from annotatin box actor to find annotation itself
void saveAnnotations(std::string filename, int mode)
save annotations to file
vtkSmartPointer< vtkBalloonWidget > m_balloonWidget
void remove(Annotation *anno)
void preserve(size_t num=0)
void updateLabels(Annotation *anno, bool resetFlag=false)
void updateBalloonByAnno(Annotation *anno)
std::vector< Annotation * > & getAnnotations()
int * m_labeledCloudIndex
int getAnnotationIndex(Annotation *anno)
BoxLabel getBoxLabel()
getBoxLabel get boxLabel from annotaion tranformation
void applyTransform(vtkSmartPointer< vtkTransform > t)
apply transform to annotation
void picked(vtkRenderWindowInteractor *interactor)
enter picked state, show boxwidget which allow to adjust annotation
static std::size_t GetTypeIndex(std::string type_)
GetTypeIndex auto add to vector map if has not.
static std::vector< std::string > * GetTypes()
get types vector pointer
static std::vector< std::string > * types
types all annotation type here
Annotation(const std::vector< int > &slice, std::string type_)
Annotation construct from slice which load from label file.
vtkSmartPointer< vtkActor > getActor() const
void colorAnnotation(int color_index=-1)
color the annotation with given color
void unpicked()
disable boxWidget
void setAnchorPoint(const PointCloudI::Ptr cloud, const std::vector< int > &slice)
copy selected points as anchor to current annotation
void adjustToAnchor()
keep current orientation, re-compute the center and scale to make annotation fit to selected point we...
std::string getType() const
double computeScaleAndCenterShift(double o[3], double scs[2])
computeScaleAndCenterShift
const std::vector< int > & getSlice() const
void setType(const std::string value)
change the type of annotation, and color too
static std::string GetTypeByIndex(size_t index)
GetTypeByIndex auto add to vector map if has not.
static void ComputeOBB(const PointCloudI::Ptr cloud, std::vector< int > &slice, double p1[3], double p2[3])
ComputeOBB compute max,min [x,y,z] aligned to xyz axis.
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
static bool Print(const char *format,...)
Prints out a formatted message in console.
static bool Error(const char *format,...)
Display an error dialog with formatted message.
CLOUDVIEWER_HOST_DEVICE float Cross(const Point &a, const Point &b)
std::string to_string(const T &n)
struct BoxLabel::@53::@55 detail