updateNodeInGraph
함수와 관련된 여러 함수를 통해updateNodeInGraph
:
mergeList
:
updateObjectGeometry
:
updateNodeCentroid
:
이 코드는 그래프 내 노드의 메쉬 연결 정보와 기하학적 속성(중심점, 경계 상자)을 업데이트하는 일련의 과정을 수행합니다. 이를 통해 노드가 메쉬 데이터에 맞게 정확히 업데이트되며, 이러한 과정은 로봇이나 3D 공간에서의 객체 추적 및 관리에 매우 유용합니다.
updateNodeInGraph
함수void MeshSegmenter::updateNodeInGraph(DynamicSceneGraph& graph,
const Cluster& cluster,
const SceneGraphNode& node,
uint64_t timestamp) {
auto& attrs = node.attributes<ObjectNodeAttributes>();
attrs.last_update_time_ns = timestamp;
attrs.is_active = true;
mergeList(attrs.mesh_connections, cluster.indices);
updateObjectGeometry(*graph.mesh(), attrs);
}
목적: 이 함수는 주어진 클러스터와 기존 노드의 메쉬 연결 정보를 병합하고, 해당 노드의 기하학적 속성(예: 중심점, 경계 상자)을 업데이트합니다.
주요 단계:
속성 업데이트:
node.attributes<ObjectNodeAttributes>()
: 해당 노드의 속성(ObjectNodeAttributes
)을 가져옵니다.attrs.last_update_time_ns = timestamp;
: 노드의 최종 업데이트 시간을 현재 타임스탬프로 설정합니다.attrs.is_active = true;
: 노드를 활성 상태로 설정합니다.메쉬 연결 병합:
mergeList(attrs.mesh_connections, cluster.indices);
: 기존 노드의 메쉬 연결 정보와 클러스터의 메쉬 인덱스 목록을 병합합니다.기하학적 속성 업데이트:
updateObjectGeometry(*graph.mesh(), attrs);
: 노드의 기하학적 속성(중심점과 경계 상자)을 업데이트합니다. mergeList
함수void mergeList(LList& lhs, const RList& rhs) {
std::unordered_set<size_t> seen(lhs.begin(), lhs.end());
for (const auto idx : rhs) {
if (seen.count(idx)) {
continue;
}
lhs.push_back(idx);
seen.insert(idx);
}
}
lhs
: 기존의 리스트 (여기에 새로운 인덱스들이 추가됩니다).rhs
: 추가할 인덱스들을 포함한 리스트.unordered_set
(seen)으로 변환하여 중복 체크에 사용합니다.rhs
의 각 인덱스를 확인하면서, 중복되지 않는 경우에만 lhs
에 추가합니다.continue
).updateObjectGeometry
함수bool updateObjectGeometry(const spark_dsg::Mesh& mesh,
ObjectNodeAttributes& attrs,
const std::vector<size_t>* indices,
std::optional<BoundingBox::Type> type) {
std::vector<size_t> mesh_connections;
if (!indices) {
mesh_connections.assign(attrs.mesh_connections.begin(),
attrs.mesh_connections.end());
}
const BoundingBox::MeshAdaptor adaptor(mesh, indices ? indices : &mesh_connections);
attrs.bounding_box = BoundingBox(adaptor, type.value_or(attrs.bounding_box.type));
if (indices) {
return updateNodeCentroid(mesh, *indices, attrs);
} else {
return updateNodeCentroid(mesh, mesh_connections, attrs);
}
}
목적: 노드의 메쉬 연결 정보를 기반으로 경계 상자(bounding box)와 중심점(centroid)을 업데이트하는 역할을 합니다.
주요 단계:
메쉬 연결 정보 설정:
indices
가 주어졌다면 해당 인덱스를 사용하고, 그렇지 않다면 attrs.mesh_connections
에 저장된 메쉬 연결 정보를 사용합니다.경계 상자 업데이트:
BoundingBox::MeshAdaptor
를 사용하여, 메쉬 정보를 기반으로 경계 상자를 계산합니다.attrs.bounding_box = BoundingBox(adaptor, type.value_or(attrs.bounding_box.type));
: 경계 상자를 업데이트합니다. 여기서 type
이 주어지면 이를 사용하고, 그렇지 않으면 기존 경계 상자 타입을 사용합니다.중심점 업데이트:
updateNodeCentroid
함수를 사용해 메쉬 연결 정보를 기반으로 노드의 중심점을 업데이트합니다.updateNodeCentroid
함수bool updateNodeCentroid(const spark_dsg::Mesh& mesh,
const std::vector<size_t>& indices,
NodeAttributes& attrs) {
size_t num_valid = 0;
Eigen::Vector3d centroid = Eigen::Vector3d::Zero();
for (const auto idx : indices) {
const auto pos = mesh.pos(idx).cast<double>();
if (!pos.array().isFinite().all()) {
continue;
}
centroid += pos;
++num_valid;
}
if (!num_valid) {
return false;
}
attrs.position = centroid / num_valid;
return true;
}
목적: 이 함수는 메쉬 연결 정보를 기반으로 노드의 중심점(centroid)을 계산하여 업데이트하는 역할을 합니다.
주요 단계:
유효한 메쉬 인덱스 검사:
pos.array().isFinite().all()
: 좌표가 유효한 값인지 확인합니다. 유효하지 않다면 그 좌표는 건너뜁니다(continue
).중심점 계산:
centroid
에 좌표를 더해줍니다.num_valid
에 기록합니다.평균 중심점 계산:
false
를 반환합니다.위 코드는 MeshSegmenter 클래스에서 새로운 노드를 그래프에 추가하고, 메쉬와 관련된 기하학적 정보(경계 상자 및 중심점)를 업데이트하는 과정을 설명합니다. 이 과정은 주어진 클러스터에 대해 새로운 객체 노드를 생성하고, 해당 노드의 속성을 설정하며, 객체의 기하학적 속성을 계산하는 절차로 구성됩니다.
addNodeToGraph
함수이 함수는 주어진 클러스터의 정보에 따라 새로운 객체 노드를 그래프에 추가하는 역할을 합니다. 클러스터는 3D 공간에서 여러 포인트의 집합으로, 이를 기반으로 노드를 생성하고, 기하학적 속성을 설정한 뒤, 그래프에 삽입합니다.
빈 클러스터 처리:
cluster.indices.empty()
), 즉 클러스터가 비어 있다면, 에러 메시지를 출력하고 함수를 종료합니다.if (cluster.indices.empty()) {
LOG(ERROR) << "Encountered empty cluster with label" << static_cast<int>(label)
<< " @ " << timestamp << "[ns]";
return;
}
객체 노드 속성 초기화:
ObjectNodeAttributes
구조체를 사용해 새로운 속성 객체(attrs)를 생성하고, 여러 속성들을 설정합니다.timestamp
, is_active
등의 기본 정보를 설정합니다.semantic_label
: 객체에 레이블(semantic label)을 부여합니다. 이 레이블은 객체가 어떤 카테고리에 속하는지를 나타냅니다.name
: 노드의 이름을 설정합니다. GlobalInfo
를 통해 레이블에 해당하는 이름을 찾고, 해당 이름이 없다면 디폴트로 NodeSymbol
을 사용해 노드 ID에 기반한 이름을 설정합니다.auto attrs = std::make_unique<ObjectNodeAttributes>();
attrs->last_update_time_ns = timestamp;
attrs->is_active = true;
attrs->semantic_label = label;
attrs->name = NodeSymbol(next_node_id_).getLabel();
const auto& label_to_name = GlobalInfo::instance().getLabelToNameMap();
auto iter = label_to_name.find(label);
if (iter != label_to_name.end()) {
attrs->name = iter->second;
} else {
VLOG(2) << "Missing semantic label from map: " << std::to_string(label);
}
메쉬 연결 정보 설정:
attrs->mesh_connections
: 클러스터에서 얻은 메쉬 연결 정보를 노드의 속성에 추가합니다. 여기서 mesh_connections
는 노드가 어떤 메쉬 인덱스들과 연결되는지에 대한 정보를 저장하는 리스트입니다.attrs->mesh_connections.insert(
attrs->mesh_connections.begin(), cluster.indices.begin(), cluster.indices.end());
객체 색상 설정:
label_map
을 사용해 객체의 레이블에 맞는 색상을 설정합니다. GlobalInfo
에서 레이블-색상 맵을 가져와 사용하며, 색상이 유효하지 않다면 랜덤한 색상 맵을 생성합니다.auto label_map = GlobalInfo::instance().getSemanticColorMap();
if (!label_map || !label_map->isValid()) {
label_map = GlobalInfo::instance().setRandomColormap();
CHECK(label_map != nullptr);
}
attrs->color = label_map->getColorFromLabel(label);
객체의 기하학적 속성 업데이트:
updateObjectGeometry
함수를 호출해 객체의 경계 상자와 중심점을 업데이트합니다. 이때 graph.mesh()
를 사용해 메쉬 정보를 가져와 계산에 사용합니다.updateObjectGeometry(*graph.mesh(), *attrs, nullptr, config.bounding_box_type);
그래프에 노드 추가:
graph.emplaceNode
를 사용해 새로 생성한 노드를 그래프에 삽입합니다. 그리고 해당 노드를 활성 노드 목록에 추가합니다. 마지막으로 노드 ID를 증가시켜, 다음에 생성할 노드에 대비합니다.graph.emplaceNode(config.layer_id, next_node_id_, std::move(attrs));
active_nodes_.at(label).insert(next_node_id_);
++next_node_id_;
updateObjectGeometry
함수이 함수는 주어진 메쉬 정보를 사용해 객체의 기하학적 속성(경계 상자와 중심점)을 업데이트합니다.
메쉬 연결 정보 설정:
indices
가 주어지면 그 값을 사용하고, 그렇지 않다면 기존의 메쉬 연결 정보를 사용합니다.std::vector<size_t> mesh_connections;
if (!indices) {
mesh_connections.assign(attrs.mesh_connections.begin(),
attrs.mesh_connections.end());
}
경계 상자 업데이트:
BoundingBox::MeshAdaptor
를 사용해, 메쉬 정보를 경계 상자로 변환합니다. 여기서 type
인자는 경계 상자의 타입(AABB, OBB 등)을 정의하는 선택적 매개변수입니다.const BoundingBox::MeshAdaptor adaptor(mesh, indices ? indices : &mesh_connections);
attrs.bounding_box = BoundingBox(adaptor, type.value_or(attrs.bounding_box.type));
중심점 업데이트:
updateNodeCentroid
함수를 사용해 주어진 메쉬 연결 정보를 기반으로 중심점을 계산하고 업데이트합니다.indices
가 주어졌다면 이를 사용해 중심점을 계산하고, 그렇지 않다면 기존 메쉬 연결 정보를 사용합니다.if (indices) {
return updateNodeCentroid(mesh, *indices, attrs);
} else {
return updateNodeCentroid(mesh, mesh_connections, attrs);
}
addNodeToGraph
함수는 새로운 클러스터에 대해 새로운 객체 노드를 생성하고, 해당 노드의 속성(레이블, 이름, 메쉬 연결 정보 등)을 설정합니다.updateObjectGeometry
함수를 사용해 기하학적 속성(경계 상자 및 중심점)을 계산합니다.updateObjectGeometry
함수는 객체의 메쉬 정보를 기반으로 경계 상자를 계산하고, 중심점을 업데이트하는 역할을 합니다.이 과정을 통해 메쉬 데이터를 기반으로 객체를 그래프에 삽입하고, 해당 객체의 기하학적 속성을 갱신하여 3D 공간에서의 정확한 위치와 크기를 파악할 수 있게 됩니다.
merged_nodes
라는 셋(Set)을 사용하여 이미 병합된 노드를 기록합니다. 이 기록을 통해 이미 병합된 노드를 중복 처리하는 것을 방지합니다.std::set<NodeId> merged_nodes;
active_nodes_
는 각 레이블에 대한 활성 노드를 기록하는 맵입니다. 주어진 레이블(label)에 속하는 활성화된 노드 리스트를 가져오며, 병합 과정을 이 리스트에 대해 수행합니다.auto& curr_active = active_nodes_.at(label);
merged_nodes
에 포함되어 있으므로, 이를 확인하여 중복 처리를 방지합니다.for (const auto& node_id : curr_active) {
if (merged_nodes.count(node_id)) {
continue;
}
const auto& node = graph.getNode(node_id);
현재 순회 중인 노드에 대해 병합이 가능한 다른 노드들을 탐색합니다. 다른 노드들과 비교하여, 두 노드가 유사하거나 겹치는지를 확인하는데, 이를 위해 nodesMatch
함수를 사용합니다.
nodesMatch
함수는 객체의 경계 상자 등을 사용하여 두 노드가 같은 객체를 나타내는지 판단하는 역할을 합니다.
만약 노드들이 일치하거나 겹친다면, 해당 노드는 병합 대상으로 추가됩니다.
std::list<NodeId> to_merge;
for (const auto& other_id : curr_active) {
if (node_id == other_id) {
continue;
}
if (merged_nodes.count(other_id)) {
continue;
}
const auto& other = graph.getNode(other_id);
if (nodesMatch(node, other) || nodesMatch(other, node)) {
to_merge.push_back(other_id);
}
}
to_merge
)에 대해, 메쉬 연결 정보(mesh_connections)를 병합합니다. 이를 통해 하나의 객체가 속한 모든 메쉬 포인트 정보가 병합된 노드에 포함됩니다.mergeList
함수를 사용해 메쉬 연결 정보 리스트를 병합합니다.merged_nodes
에 해당 노드를 기록하여 중복 처리 방지에 사용됩니다.auto& attrs = node.attributes<ObjectNodeAttributes>();
for (const auto& other_id : to_merge) {
const auto& other = graph.getNode(other_id);
auto& other_attrs = other.attributes<ObjectNodeAttributes>();
mergeList(attrs.mesh_connections, other_attrs.mesh_connections);
graph.removeNode(other_id);
merged_nodes.insert(other_id);
}
updateObjectGeometry
함수를 호출하여 객체의 기하학적 속성을 업데이트합니다. 이 함수는 메쉬 정보를 사용해 객체의 경계 상자와 중심점을 계산합니다.if (!to_merge.empty()) {
updateObjectGeometry(*graph.mesh(), attrs);
}
for (const auto& node_id : merged_nodes) {
curr_active.erase(node_id);
}