ゆいのあ氏(@yuinore)が書いた↓の記事を見て、C++だとどれくらい長くなるのかな~と適当につぶやいたところ、うえぽん氏(@imaginary_uepon)が勢いで書いてくれました。

うえぽん氏が長くなるよう?Windows Imaging Componentを使って低レイヤーな部分も含めて書いてくれたので、私はOpenCVを使うとどれくらい短くなるか試してみました(ぶち壊し…)。

プログラム

以下がOpenCVでアクリルキーホルダーの重心を調べるプログラムです。

#include <iostream>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/core.hpp>

int main()
{
    cv::Mat image = imread("image.png", cv::IMREAD_UNCHANGED);

    // アルファ値を重みとした座標合計, およびアルファ値の合計を算出
    cv::Vec2d posSum(0, 0);
    double alphaSum = 0;
    for (int i = 0; i < image.rows; ++i)
    {
        for (int j = 0; j < image.cols; ++j)
        {
            double alpha = image.at<cv::Vec4b>(i, j)[3] / 255.0;
            posSum += cv::Vec2d(j, i) * alpha;
            alphaSum += alpha;
        }
    }

    if (alphaSum > 0)
    {
        // 座標の重み付き平均(=重心)を算出
        cv::Vec2d center = posSum / alphaSum;

        // ピクセルの大きさを考慮して0.5px右下にずらす
        center += cv::Vec2d(0.5, 0.5);

        std::cout << center << std::endl;
    }
    else
    {
        std::cout << "error: no alpha" << std::endl;
    }

    return 0;
}

40行くらい。
OpenCVはアルファブレンド付き画像に完全対応しているわけではないようなので、アルファ値をとるにはIMREAD_UNCHANGEDで読み込む必要があります。
この際、エンディアンの影響なのか縦横が逆になったりr/g/bが逆向き(BGRA)になったりするので注意が必要です。

試してみる

適当に描いた画像で試してみたところ、以下の座標になりました。だいたいあってそう。


この投稿をシェアする