Эх сурвалжийг харах

modified: Make ImageHasher::hammingDistance() inline.

Satoshi Yoneda 3 долоо хоног өмнө
parent
commit
662ff1cf9e
2 өөрчлөгдсөн 79 нэмэгдсэн , 69 устгасан
  1. 16 14
      include/ImageHasher.hpp
  2. 63 55
      src/ImageHasher.cpp

+ 16 - 14
include/ImageHasher.hpp

@@ -1,27 +1,29 @@
 #pragma once
+#include <cstdint>
 #include <opencv2/opencv.hpp>
 #include <string>
 #include <vector>
-#include <cstdint>
 
 class ImageHasher {
 public:
-    // dHash(隣接ピクセルの輝度差分によるハッシュ)を計算する
-    // 戻り値: 64ビット整数値のハッシュ
-    static uint64_t calculateDHash(const cv::Mat& image);
+  // dHash(隣接ピクセルの輝度差分によるハッシュ)を計算する
+  // 戻り値: 64ビット整数値のハッシュ
+  static uint64_t calculateDHash(const cv::Mat &image);
 
-    // pHash(DCT: 離散コサイン変換を用いた周波数特徴ハッシュ)を計算する
-    // 戻り値: 64ビット整数値のハッシュ
-    static uint64_t calculatePHash(const cv::Mat& image);
+  // pHash(DCT: 離散コサイン変換を用いた周波数特徴ハッシュ)を計算する
+  // 戻り値: 64ビット整数値のハッシュ
+  static uint64_t calculatePHash(const cv::Mat &image);
 
-    // 2つのハッシュ値間のハミング距離(異なるビットの数)を計算する
-    static int hammingDistance(uint64_t h1, uint64_t h2);
+  // 2つのハッシュ値間のハミング距離(異なるビットの数)を計算する
+  static inline int hammingDistance(uint64_t h1, uint64_t h2) {
+    return static_cast<int>(std::popcount(h1 ^ h2));
+  };
 
-    // 大容量画像を高速に読み込むためのヘルパー関数
-    // targetSize: 縮小後の目安となる最大サイズ
-    static cv::Mat loadImage(const std::string& path, int targetSize = 512);
+  // 大容量画像を高速に読み込むためのヘルパー関数
+  // targetSize: 縮小後の目安となる最大サイズ
+  static cv::Mat loadImage(const std::string &path, int targetSize = 512);
 
 private:
-    static constexpr int DHASH_SIZE = 8;
-    static constexpr int PHASH_SIZE = 32;
+  static constexpr int DHASH_SIZE = 8;
+  static constexpr int PHASH_SIZE = 32;
 };

+ 63 - 55
src/ImageHasher.cpp

@@ -1,77 +1,85 @@
 #include "ImageHasher.hpp"
-#include <opencv2/imgproc.hpp>
 #include <bit> // C++20 std::popcount
+#include <opencv2/imgproc.hpp>
 
-// 画像の輝度勾配(隣り合うピクセルの明暗)からハッシュを計算する(Difference Hash)
-// 処理が軽く、単純なリサイズ等に強い特徴がある
-uint64_t ImageHasher::calculateDHash(const cv::Mat& image) {
-    if (image.empty()) return 0;
+// 画像の輝度勾配(隣り合うピクセルの明暗)からハッシュを計算する(Difference
+// Hash) 処理が軽く、単純なリサイズ等に強い特徴がある
+uint64_t ImageHasher::calculateDHash(const cv::Mat &image) {
+  if (image.empty())
+    return 0;
 
-    cv::Mat gray, resized;
-    cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
-    // dHash needs 9x8 for 8x8 diffs
-    cv::resize(gray, resized, cv::Size(9, 8));
+  cv::Mat gray, resized;
+  cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
+  // dHash needs 9x8 for 8x8 diffs
+  cv::resize(gray, resized, cv::Size(9, 8));
 
-    uint64_t hash = 0;
-    for (int y = 0; y < 8; ++y) {
-        for (int x = 0; x < 8; ++x) {
-            if (resized.at<uint8_t>(y, x) < resized.at<uint8_t>(y, x + 1)) {
-                hash |= (1ULL << (y * 8 + x));
-            }
-        }
+  uint64_t hash = 0;
+  for (int y = 0; y < 8; ++y) {
+    for (int x = 0; x < 8; ++x) {
+      if (resized.at<uint8_t>(y, x) < resized.at<uint8_t>(y, x + 1)) {
+        hash |= (1ULL << (y * 8 + x));
+      }
     }
-    return hash;
+  }
+  return hash;
 }
 
-// 画像の低周波成分(全体的な形状やぼんやりとした特徴)からハッシュを計算する(Perceptual Hash)
-// 多少の色調変化やノイズに対してよりロバスト(堅牢)な特徴がある
-uint64_t ImageHasher::calculatePHash(const cv::Mat& image) {
-    if (image.empty()) return 0;
+// 画像の低周波成分(全体的な形状やぼんやりとした特徴)からハッシュを計算する(Perceptual
+// Hash) 多少の色調変化やノイズに対してよりロバスト(堅牢)な特徴がある
+uint64_t ImageHasher::calculatePHash(const cv::Mat &image) {
+  if (image.empty())
+    return 0;
 
-    cv::Mat gray, resized, floatImg, dctImg;
-    cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
-    // Resize to 32x32 for DCT
-    cv::resize(gray, resized, cv::Size(PHASH_SIZE, PHASH_SIZE));
-    resized.convertTo(floatImg, CV_32F);
-    
-    cv::dct(floatImg, dctImg);
+  cv::Mat gray, resized, floatImg, dctImg;
+  cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
+  // Resize to 32x32 for DCT
+  cv::resize(gray, resized, cv::Size(PHASH_SIZE, PHASH_SIZE));
+  resized.convertTo(floatImg, CV_32F);
 
-    // Take top-left 8x8 (excluding DC component at 0,0)
-    double sum = 0;
-    for (int y = 0; y < 8; ++y) {
-        for (int x = 0; x < 8; ++x) {
-            if (x == 0 && y == 0) continue;
-            sum += dctImg.at<float>(y, x);
-        }
+  cv::dct(floatImg, dctImg);
+
+  // Take top-left 8x8 (excluding DC component at 0,0)
+  double sum = 0;
+  for (int y = 0; y < 8; ++y) {
+    for (int x = 0; x < 8; ++x) {
+      if (x == 0 && y == 0)
+        continue;
+      sum += dctImg.at<float>(y, x);
     }
-    double avg = sum / 63.0;
+  }
+  double avg = sum / 63.0;
 
-    uint64_t hash = 0;
-    for (int y = 0; y < 8; ++y) {
-        for (int x = 0; x < 8; ++x) {
-            if (x == 0 && y == 0) continue;
-            if (dctImg.at<float>(y, x) > avg) {
-                hash |= (1ULL << (y * 8 + x));
-            }
-        }
+  uint64_t hash = 0;
+  for (int y = 0; y < 8; ++y) {
+    for (int x = 0; x < 8; ++x) {
+      if (x == 0 && y == 0)
+        continue;
+      if (dctImg.at<float>(y, x) > avg) {
+        hash |= (1ULL << (y * 8 + x));
+      }
     }
-    return hash;
+  }
+  return hash;
 }
 
 // ハミング距離を計算する (std::popcount でハードウェア命令を使い高速化)
+/*
 int ImageHasher::hammingDistance(uint64_t h1, uint64_t h2) {
     return static_cast<int>(std::popcount(h1 ^ h2));
 }
+*/
 
-cv::Mat ImageHasher::loadImage(const std::string& path, int targetSize) {
-    // Load with IMREAD_COLOR
-    cv::Mat img = cv::imread(path, cv::IMREAD_COLOR);
-    if (img.empty()) return cv::Mat();
+cv::Mat ImageHasher::loadImage(const std::string &path, int targetSize) {
+  // Load with IMREAD_COLOR
+  cv::Mat img = cv::imread(path, cv::IMREAD_COLOR);
+  if (img.empty())
+    return cv::Mat();
 
-    // Minor optimization: if image is huge, resize it slightly for faster hashing
-    if (img.cols > targetSize || img.rows > targetSize) {
-        double scale = static_cast<double>(targetSize) / std::max(img.cols, img.rows);
-        cv::resize(img, img, cv::Size(), scale, scale);
-    }
-    return img;
+  // Minor optimization: if image is huge, resize it slightly for faster hashing
+  if (img.cols > targetSize || img.rows > targetSize) {
+    double scale =
+        static_cast<double>(targetSize) / std::max(img.cols, img.rows);
+    cv::resize(img, img, cv::Size(), scale, scale);
+  }
+  return img;
 }