0

私のアプリケーションの問題は、約 500 個の画像を取得できることですが、2 つの画像のペアのうち 1 つまたは 2 つが完全に同じである可能性があります。これは、ファイルのチェックサムが同じであることを意味します。私の最終的な目標は、どれが繰り返された画像のパリであるかを見つけることです.

しかし、これらの 500 個の画像に圧縮アルゴリズムを適用する必要があります。これは、圧縮されていない画像がディスク領域を占有しすぎるためです。圧縮によってチェックサムが破られるため、圧縮された画像ファイルのチェックサムを使用して、繰り返される画像のペアを特定することはできません。

幸いなことに、私の圧縮アルゴリズムは無損失です。これは、復元された非圧縮画像を何らかの方法でハッシュできることを意味します。しかし、ディスクへの書き込みアクセスをあまり行わずに、これをメモリ内で実行したいだけです。だから私の問題は、メモリ内の多数の画像ファイルから繰り返し画像を効率的に取得する方法ですか?

私はopencvをよく使用しますが、ディスクにファイルを保存せずに効率的である限り、答えは良いでしょう。Python/Bash コードも受け入れられます。C/C++ と OpenCV が推奨されます。

std::hash で OpenCV の Mat を使用することを考えることができますが、 std::hash は直接std::hash<cv::Mat>動作しません。具体的にコーディングする必要があり、適切に行う方法はまだわかりません。

もちろん、私はこれを行うことができます、

For each 2 images in all my images:
            if ((cv::Mat)img1 == (cv::Mat)img2):
                   print img1 and img2 are identical

しかし、これは非常に非効率的で、基本的に ^4 アルゴリズムです。

私の問題は画像の類似性の問題ではなく、memroy のハッシュの問題であることに注意してください。

4

3 に答える 3

1

image のハッシュアルゴリズムを取得するアイデア:

  1. 元の画像のサイズを縮小 (cvResize ()) して、重要なオブジェクトのみが画像に残るようにします (高周波を取り除きます)。画像を 8x8 に縮小すると、ピクセルの総数は 64 になり、サイズや縦横比に関係なく、ハッシュはすべての種類の画像に適合します。

  2. 色を取り除きます。前の手順で取得した画像をグレースケールに変換します。(cvCvtColor ())。したがって、ハッシュは 192 (赤、緑、青の 3 つのチャネルの 64 の値) から 64 の明るさの値に減少します。

  3. 結果の画像の平均の明るさを見つけます。(cvAvg ())

  4. 画像の二値化。(cvThreshold ()) は、平均よりも大きいピクセルのみを保持します (それらは 1 と見なされ、その他はすべて 0 と見なされます)。

  5. ハッシュの構築。1 画像と 0 画像の 64 個の値を 1 つの 64 ビット ハッシュ値に変換したもの。

次に、2 つの画像を比較する必要がある場合は、それぞれの画像のハッシュを作成し、異なるビットの数を数えます (ハミング距離を使用)。ハミング距離 - 同じ長さの 2 つのバイナリ ワードのそれぞれの数が異なる位置の数。

距離が 0 の場合は、同じ画像である可能性が高く、他の値は互いにどの程度異なるかを表します。

于 2013-09-19T06:43:32.483 に答える
0

OK、私は自分で解決策を見つけました。さらに良い解決策があれば歓迎します。ここにコードを貼り付けます。

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <functional>
#include <openssl/md5.h>

using namespace std;
using namespace cv;

static void help()
{
}

char *str2md5(const char *str, int length) {
    int n;
    MD5_CTX c;
    unsigned char digest[16];
    char *out = (char*)malloc(33);

    MD5_Init(&c);

    while (length > 0) {
        if (length > 512) {
            MD5_Update(&c, str, 512);
        } else {
            MD5_Update(&c, str, length);
        }
        length -= 512;
        str += 512;
    }

    MD5_Final(digest, &c);

    for (n = 0; n < 16; ++n) {
        snprintf(&(out[n*2]), 16*2, "%02x", (unsigned int)digest[n]);
    }

    return out;
}


int main(int argc, const char** argv)
{
    help();

    if (argc != 2)
    {
        return EXIT_FAILURE ;
    }

    string inputfile = argv[1] ;

    Mat src = imread (inputfile, -1) ;

    if (src.empty())
    {
        return EXIT_FAILURE ;
    }



    cout << str2md5((char*)src.data, (int)src.step[0] * src.rows) << " " << inputfile << endl ;




    return 0;
}

このコードをコンパイルするには、マシンに OpenSSL (libssl-dev) をインストールする必要があります。イメージをメモリにロードし、その md5 値を計算します。したがって、繰り返し画像のペアを見つけるには、コンパイルされたプログラムを使用して単純な bash/python スクリプトを記述し、ファイルの md5 値配列を検索します。この md5 チェック コードは、巨大な画像ファイルでは機能しないことに注意してください。

于 2013-09-23T03:50:30.290 に答える
0

必要な画像の正確なコピーである場合は、すべての画像のピクセル 1,1 の比較を開始し、ピクセル 1,1 の同じ値でそれらをグループ化できます。その後、グループ (できればかなり多くのグループ) を把握し、各グループのピクセルを比較します 1,2 。このようにして、100 個ほどのグループが得られるまで、ピクセルごとに処理を行います。各グループで、それらを完全に比較するだけではありません。そうすれば、遅い n^4 アルゴリズムを実行できますが、一度に 500 枚の画像ではなく、毎回 5 枚の画像のグループに対して行われます。画像をピクセルごとに読み取ることができると仮定しています.pyfitsモジュールを使用して.fitsにある場合は可能ですが、ほとんどすべての画像形式に代替手段が存在すると思いますか?

したがって、この背後にある考え方は、ピクセル 1,1 が異なる場合、画像全体が異なるということです。このようにして、おそらく最初の 3 ピクセル程度の値でリストを作成できます。そのリストに十分な変動がある場合は、一度に 500 個の画像ではなく、はるかに小さなグループの画像に対して 1 対 1 の完全な画像チェックを行うことができます。これは、あなたが望むことをするべきだと思いますか?

于 2013-09-19T08:53:30.073 に答える