OpenSfM关键代码学习笔记

灰色文字


前言

OpenSfM是一个用于三维重建的三维软件,它用Python实现了Structure-from-Motion算法。
该软件的使用方法见之前的一篇博客
Structure-from-Motion算法中较重要的三步是:特征点检测、特征点匹配、增量式重建。OpenSfM的整个重建可以通过在终端中输入特定命令来实现。OpenSfM提供的一些命令包括:

	extract_metadata      # Extract metadata form images' EXIF tag
    detect_features       # Compute features for all images
    match_features        # Match features between image pairs
    create_tracks         # Link matches pair-wise matches into tracks
    reconstruct           # Compute the reconstruction
    mesh                  # Add delaunay meshes to the reconstruction
    undistort             # Save radially undistorted images
    compute_depthmaps     # Compute depthmap
    export_ply            # Export reconstruction to PLY format
    export_openmvs        # Export reconstruction to openMVS format
    export_visualsfm      # Export reconstruction to NVM_V3 format from VisualSfM

而特征点检测、特征点匹配、增量式重建分别对应着detect_features、match_features、reconstruct命令。
下面记录了我查看这三步操作的源码时的笔记。


1 关键步骤的具体方法概览

以下所列举的方法都是OpenSfM默认设置的方法。如果有自己调参的需求,某些步骤在config文件里也可以自己选用其他方法、其他参数。

  1. 特征点检测
    特征点检测:covdet (covariance descriptor)
    构建描述符:sift (scale invariant feature transform)
    依赖:VLFeat
    依赖源码语言:C++ (需Python binding)
points, desc = pyfeatures.hahog(image.astype(np.float32) / 255,  # VlFeat expects pixel values between 0, 1
                              peak_threshold=config['hahog_peak_threshold'],
                              edge_threshold=config['hahog_edge_threshold'],
                              target_num_features=config['feature_min_frames'],
                              use_adaptive_suppression=config['feature_use_adaptive_suppression'])
  1. 特征点匹配:FLANN (Fast Approximate Nearest Neighbor Search)
    依赖:OpenCV
    依赖源码语言:Python
  2. Bundle Adjustment:Ceres
    依赖:Ceres
    依赖源码语言:C++(需Python binding)
linear_solver_type_ = "SPARSE_NORMAL_CHOLESKY";

2 特征点检测

2.1 detect_feature命令

程序最外层直接调用的命令文件detect_feature.py内容如下:

# opensfm/commands/detect_feature.py文件全部内容
import logging
from timeit import default_timer as timer

import numpy as np

from opensfm import bow
from opensfm import dataset
from opensfm import features
from opensfm import io
from opensfm import log
from opensfm.context import parallel_map

logger = logging.getLogger(__name__)

class Command:
    name = 'detect_features'
    help = 'Compute features for all images'

    def add_arguments(self, parser):
        parser.add_argument('dataset', help='dataset to process')

    def run(self, args):
        data = dataset.DataSet(args.dataset)
        images = data.images()

        arguments = [(image, data) for image in images]

        start = timer()
        processes = data.config['processes']
        parallel_map(detect, arguments, processes, 1)  #重点!
        end = timer()
        with open(data.profile_log(), 'a') as fout:
            fout.write('detect_features: {0}\n'.format(end - start))

        self.write_report(data, end - start)

    def write_report(self, data, wall_time):
        image_reports = []
        for image in data.images():
            try:
                txt = data.load_report('features/{}.json'.format(image))
                image_reports.append(io.json_loads(txt))
            except IOError:
                logger.warning('No feature report image {}'.format(image))

        report = {
   
            "wall_time": wall_time
  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
首先,感谢您对eclipse插件开发学习的关注!下面是一些学习笔记配套代码的例子。 1. 创建一个最简单的插件: ```java public class HelloWorldPlugin implements IStartup { @Override public void earlyStartup() { System.out.println("Hello, Eclipse Plugin Development!"); } } ``` 2. 在Eclipse菜单中添加一个新的命令: ```java public class MyCommandHandler extends AbstractHandler { @Override public Object execute(ExecutionEvent event) throws ExecutionException { MessageDialog.openInformation(HandlerUtil.getActiveWorkbenchWindow(event).getShell(), "My Command", "Hello, Eclipse Plugin Development!"); return null; } } ``` 3. 在编辑器右键菜单中添加一个新的动作: ```java public class MyEditorAction extends Action { public MyEditorAction() { setText("My Action"); } @Override public void run() { IEditorPart editor = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor(); if (editor instanceof ITextEditor) { ITextEditor textEditor = (ITextEditor) editor; IDocumentProvider documentProvider = textEditor.getDocumentProvider(); IDocument document = documentProvider.getDocument(textEditor.getEditorInput()); selectCurrentWord(textEditor, document); } } private void selectCurrentWord(ITextEditor editor, IDocument document) { ISelectionProvider selectionProvider = editor.getSelectionProvider(); ITextSelection selection = (ITextSelection) selectionProvider.getSelection(); int offset = selection.getOffset(); try { int lineStartOffset = document.getLineOffset(selection.getStartLine()); int lineEndOffset = lineStartOffset + document.getLineLength(selection.getStartLine()); String lineText = document.get(lineStartOffset, lineEndOffset - lineStartOffset); int wordStartOffset = lineText.lastIndexOf(' ', offset - lineStartOffset) + 1; int wordEndOffset = lineText.indexOf(' ', offset - lineStartOffset); if (wordEndOffset < wordStartOffset) { // The word is the last or only word on the line wordEndOffset = lineEndOffset - lineStartOffset; } else { wordEndOffset += lineStartOffset; } selectionProvider.setSelection(new TextSelection(wordStartOffset, wordEndOffset - wordStartOffset)); } catch (BadLocationException e) { e.printStackTrace(); } } } ``` 此处仅提供了一些简单的示例代码,以帮助您开始使用eclipse插件开发。有关更详细的学习和开发指导,请参阅Eclipse官方文档和教程。祝您在插件开发的学习过程中取得成功!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值