ORBアルゴリズムによる画像特徴点抽出のC言語実装

ORB特徴抽出の実装手法

ORBアルゴリズムの実装には複雑な行列演算が必要なため、以下ではOpenCVを利用した方法と独自実装による簡易版の2種類のアプローチを紹介します。

OpenCVを利用した実装

ヘッダファイル定義

#ifndef ORB_FEATURE_DETECTOR_H
#define ORB_FEATURE_DETECTOR_H

#include <opencv2/core/core_c.h>

typedef struct {
    int max_features;
    float scale_factor;
    int pyramid_levels;
    int edge_margin;
    int window_size;
    int fast_thresh;
} ORB_Config;

typedef struct {
    float pos_x;
    float pos_y;
    float feature_size;
    float orientation;
    float strength;
    int pyramid_level;
} FeaturePoint;

typedef struct {
    uint8_t* descriptor_data;
    int point_count;
    int descriptor_size;
} FeatureDescriptors;

void ORB_Configure(ORB_Config* settings);
int ORB_ExtractFeatures(const char* image_path, FeaturePoint** points, FeatureDescriptors* descriptors);
void ORB_ReleasePoints(FeaturePoint* points);
void ORB_ReleaseDescriptors(FeatureDescriptors* descriptors);
void ORB_VisualizeFeatures(const char* source_path, FeaturePoint* points, int count, const char* result_path);

#endif

特徴点抽出実装

#include "orb_feature_detector.h"
#include <opencv2/imgproc/imgproc_c.h>

static ORB_Config config = {
    .max_features = 500,
    .scale_factor = 1.2f,
    .pyramid_levels = 8,
    .edge_margin = 31,
    .window_size = 31,
    .fast_thresh = 20
};

void ORB_Configure(ORB_Config* settings) {
    if (settings) memcpy(&config, settings, sizeof(ORB_Config));
}

int ORB_ExtractFeatures(const char* image_path, FeaturePoint** points, FeatureDescriptors* descriptors) {
    IplImage* src = cvLoadImage(image_path, CV_LOAD_IMAGE_COLOR);
    if (!src) return -1;
    
    IplImage* gray = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
    cvCvtColor(src, gray, CV_BGR2GRAY);
    
    CvORB* detector = cvCreateORB(config.max_features, config.scale_factor,
                                 config.pyramid_levels, config.edge_margin,
                                 config.window_size, config.fast_thresh);
    
    CvSeq* detected_points = cvDetectORB(detector, gray, NULL);
    CvSeq* computed_descriptors = cvComputeORB(detector, gray, detected_points, NULL);
    
    int count = detected_points->total;
    *points = malloc(count * sizeof(FeaturePoint));
    
    for (int i = 0; i < count; i++) {
        CvORBKeyPoint* kp = cvGetSeqElem(detected_points, i);
        (*points)[i] = (FeaturePoint){
            .pos_x = kp->pt.x,
            .pos_y = kp->pt.y,
            .feature_size = kp->size,
            .orientation = kp->angle,
            .strength = kp->response,
            .pyramid_level = kp->octave
        };
    }
    
    descriptors->point_count = count;
    descriptors->descriptor_size = 32;
    descriptors->descriptor_data = malloc(count * 32);
    
    for (int i = 0; i < count; i++) {
        uint8_t* desc = cvGetSeqElem(computed_descriptors, i);
        memcpy(descriptors->descriptor_data + i * 32, desc, 32);
    }
    
    cvReleaseORB(&detector);
    cvReleaseImage(&gray);
    cvReleaseImage(&src);
    return count;
}

簡易版独自実装

基本構造定義

#ifndef SIMPLE_FEATURE_DETECTOR_H
#define SIMPLE_FEATURE_DETECTOR_H

typedef struct {
    uint8_t* pixel_data;
    int width;
    int height;
    int channels;
} ImageData;

typedef struct {
    float x, y;
    float size;
    float angle;
    float score;
} DetectedPoint;

ImageData* LoadImageFile(const char* filename);
void FreeImageData(ImageData* img);
int SimpleFeatureDetection(ImageData* image, DetectedPoint** points, int max_points);

#endif

特徴検出ロジック

#include "simple_feature_detector.h"
#include <math.h>

static void ConvertToGrayscale(ImageData* src, ImageData* dst) {
    for (int i = 0; i < src->width * src->height; i++) {
        uint8_t r = src->pixel_data[i * 3];
        uint8_t g = src->pixel_data[i * 3 + 1];
        uint8_t b = src->pixel_data[i * 3 + 2];
        dst->pixel_data[i] = (uint8_t)(0.299 * r + 0.587 * g + 0.114 * b);
    }
}

static int DetectCorner(ImageData* gray, int x, int y, int threshold) {
    uint8_t center = gray->pixel_data[y * gray->width + x];
    int diff_count = 0;
    
    const int check_offsets[8][2] = {{3,0}, {3,3}, {0,3}, {-3,3}, {-3,0}, {-3,-3}, {0,-3}, {3,-3}};
    
    for (int i = 0; i < 8; i++) {
        int nx = x + check_offsets[i][0];
        int ny = y + check_offsets[i][1];
        uint8_t px = gray->pixel_data[ny * gray->width + nx];
        if (abs(px - center) > threshold) diff_count++;
    }
    
    return diff_count >= 6;
}

static float CalculateOrientation(ImageData* gray, int cx, int cy, int radius) {
    float total_intensity = 0, weighted_x = 0, weighted_y = 0;
    
    for (int dy = -radius; dy <= radius; dy++) {
        for (int dx = -radius; dx <= radius; dx++) {
            int x = cx + dx;
            int y = cy + dy;
            if (x >= 0 && y >= 0 && x < gray->width && y < gray->height) {
                uint8_t val = gray->pixel_data[y * gray->width + x];
                total_intensity += val;
                weighted_x += x * val;
                weighted_y += y * val;
            }
        }
    }
    
    if (total_intensity == 0) return 0;
    return atan2(weighted_y/total_intensity - cy, weighted_x/total_intensity - cx) * 180.0f / M_PI;
}

int SimpleFeatureDetection(ImageData* image, DetectedPoint** points, int max_points) {
    ImageData* gray = malloc(sizeof(ImageData));
    gray->width = image->width;
    gray->height = image->height;
    gray->channels = 1;
    gray->pixel_data = malloc(gray->width * gray->height);
    
    ConvertToGrayscale(image, gray);
    
    int capacity = 1000;
    *points = malloc(capacity * sizeof(DetectedPoint));
    int count = 0;
    
    for (int y = 3; y < gray->height-3; y += 4) {
        for (int x = 3; x < gray->width-3; x += 4) {
            if (DetectCorner(gray, x, y, 30)) {
                if (count >= capacity) {
                    capacity *= 2;
                    *points = realloc(*points, capacity * sizeof(DetectedPoint));
                }
                
                (*points)[count] = (DetectedPoint){
                    .x = x,
                    .y = y,
                    .size = 16.0f,
                    .angle = CalculateOrientation(gray, x, y, 8),
                    .score = 1.0f
                };
                count++;
                
                if (count >= max_points) break;
            }
        }
    }
    
    free(gray->pixel_data);
    free(gray);
    return count;
}

ビルド方法

# OpenCVを使用する場合
gcc -o feature_extractor main.c orb_feature_detector.c \
    `pkg-config --cflags --libs opencv4`

# 簡易版の場合
gcc -o simple_detector simple_main.c simple_feature_detector.c -lm

性能最適化手法

#pragma omp parallel for
for (int y = 0; y < image_height; y++) {
    // 行単位の並列処理
}

#ifdef __SSE2__
#include <emmintrin.h>
void OptimizedCornerDetection(uint8_t* pixels, int width, int height) {
    // SIMD命令による高速化
}
#endif

応用例

int CombineImages(const char* image1, const char* image2, const char* output) {
    FeaturePoint* points1, *points2;
    FeatureDescriptors desc1, desc2;
    
    ORB_ExtractFeatures(image1, &points1, &desc1);
    ORB_ExtractFeatures(image2, &points2, &desc2);
    
    // 特徴点マッチングと画像結合処理
    return 0;
}

タグ: ORB 特徴点抽出 OpenCV C言語 画像処理

8月15日 16:33 投稿