ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 동일한 이미지를 빠르게 식별하는 알고리즘 feat.c# code
    프로그램(C# etc.) 2023. 2. 28. 09:39

     동일한 이미지를 빠르게 식별하는 데 사용할 수 있는 다양한 알고리즘이 있습니다. 일반적으로 사용되는 알고리즘 중 하나는 Perceptual Hashing 알고리즘입니다. 작동 방식은 다음과 같습니다.

    1. 이미지 크기를 고정된 작은 크기(예: 8x8픽셀)로 조정합니다.
    2. 이미지를 회색조로 변환합니다.
    3. 각 이미지의 픽셀에 이산 코사인 변환(DCT)을 적용합니다. DCT는 공간 도메인의 픽셀 값을 주파수 도메인으로 변환합니다.
    4. 각 이미지에 대한 DCT 계수의 평균값을 계산합니다. 이 값은 계수 임계값에 사용됩니다. 계수가 평균보다 크면 1로 설정됩니다. 그렇지 않으면 0으로 설정됩니다.
    5. 임계값 계수를 단일 이진 문자열로 연결합니다. 이 문자열은 이미지의 지각 해시입니다.
    6. 해밍 거리 메트릭을 사용하여 두 이미지의 지각 해시를 비교합니다. 해밍 거리는 두 이진 문자열 간에 다른 비트 수입니다. 해밍 거리가 특정 임계값 미만이면 이미지가 동일한 것으로 간주됩니다.

     이 알고리즘은 이미지당 적은 양의 계산만 필요하기 때문에 빠르고 결과적인 지각 해시는 콤팩트합니다. 그리고 비교하기 쉽습니다. 그러나 완벽하지 않으며 경우에 따라(예: 이미지 크기가 크게 조정되거나 압축된 경우) 모든 동일한 이미지를 식별하지 못할 수 있습니다.

     

    Q2. 위 알고리즘을 c#코드로 보여줘

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Linq;
    
    public static class ImageHelper
    {
        public static byte[] GetPerceptualHash(Bitmap bitmap)
        {
            const int Size = 8;
    
            // Resize the image to a fixed size
            Bitmap resized = new Bitmap(bitmap, new Size(Size, Size));
    
            // Convert the image to grayscale
            Bitmap gray = ToGrayscale(resized);
    
            // Apply DCT to the pixel values
            double[,] dct = DCT2D(gray);
    
            // Threshold the DCT coefficients
            double mean = Mean(dct);
            bool[] bits = Threshold(dct, mean);
    
            // Convert the bits to bytes
            byte[] bytes = BitsToBytes(bits);
    
            return bytes;
        }
    
        private static Bitmap ToGrayscale(Bitmap bitmap)
        {
            Bitmap gray = new Bitmap(bitmap.Width, bitmap.Height);
    
            for (int y = 0; y < bitmap.Height; y++)
            {
                for (int x = 0; x < bitmap.Width; x++)
                {
                    Color color = bitmap.GetPixel(x, y);
                    byte grayValue = (byte)(0.299 * color.R + 0.587 * color.G + 0.114 * color.B);
                    gray.SetPixel(x, y, Color.FromArgb(grayValue, grayValue, grayValue));
                }
            }
    
            return gray;
        }
    
        private static double[,] DCT2D(Bitmap bitmap)
        {
            double[,] dct = new double[bitmap.Height, bitmap.Width];
    
            for (int v = 0; v < bitmap.Height; v++)
            {
                for (int u = 0; u < bitmap.Width; u++)
                {
                    double sum = 0.0;
    
                    for (int y = 0; y < bitmap.Height; y++)
                    {
                        for (int x = 0; x < bitmap.Width; x++)
                        {
                            Color color = bitmap.GetPixel(x, y);
                            double grayValue = (0.299 * color.R + 0.587 * color.G + 0.114 * color.B) - 128;
                            double cu = (u == 0) ? 1 / Math.Sqrt(2) : 1;
                            double cv = (v == 0) ? 1 / Math.Sqrt(2) : 1;
                            double cosU = Math.Cos(((2 * x + 1) * u * Math.PI) / (2 * bitmap.Width));
                            double cosV = Math.Cos(((2 * y + 1) * v * Math.PI) / (2 * bitmap.Height));
                            double value = cu * cv * grayValue * cosU * cosV;
                            sum += value;
                        }
                    }
    
                    double alpha = (u == 0) ? 1 / Math.Sqrt(bitmap.Width) : Math.Sqrt(2) / Math.Sqrt(bitmap.Width);
                    double beta = (v == 0) ? 1 / Math.Sqrt(bitmap.Height) : Math.Sqrt(2) / Math.Sqrt(bitmap.Height);
                    dct[v, u] = alpha * beta * sum;
                }
            }
    
            return dct;
        }
    
        private static double Mean(double[,] dct)
        {
            double sum = 0.0;
    
            for (int y = 0; y < dct.GetLength(0); y++)
            {
                for (int x = 0; x < dct.GetLength(1); x++)
                {
                    sum += dct[y, x];
                }
            }
    
            return sum / (dct.GetLength(0) * dct.GetLength(1));
    	}
        
        private static bool[] Threshold(double[,] dct, double threshold)
        {
            bool[] bits = new bool[dct.GetLength(0) * dct.GetLength(1)];
    
            for (int y = 0; y < dct.GetLength(0); y++)
            {
                for (int x = 0; x < dct.GetLength(1); x++)
                {
                    bits[y * dct.GetLength(1) + x] = (dct[y, x] > threshold);
                }
            }
    
            return bits;
        }
    
        private static byte[] BitsToBytes(bool[] bits)
        {
            byte[] bytes = new byte[bits.Length / 8];
    
            for (int i = 0; i < bytes.Length; i++)
            {
                byte value = 0;
    
                for (int j = 0; j < 8; j++)
                {
                    if (bits[i * 8 + j])
                    {
                        value |= (byte)(1 << (7 - j));
                    }
                }
    
                bytes[i] = value;
            }
    
            return bytes;
        }
    
        public static int HammingDistance(byte[] hash1, byte[] hash2)
        {
            int distance = 0;
    
            for (int i = 0; i < hash1.Length; i++)
            {
                byte xor = (byte)(hash1[i] ^ hash2[i]);
    
                for (int j = 0; j < 8; j++)
                {
                    if ((xor & (1 << (7 - j))) != 0)
                    {
                        distance++;
                    }
                }
            }
    
            return distance;
        }
    }

     

    Q2. 위 코드 사용해서 jpg파일 2개 비교하는 함수 보여줘

    using System;
    using System.Drawing;
    using System.IO;
    
    public static class ImageComparison
    {
        public static bool AreImagesIdentical(string filePath1, string filePath2, int maxHammingDistance)
        {
            // Load the images from the files
            Bitmap bitmap1 = new Bitmap(filePath1);
            Bitmap bitmap2 = new Bitmap(filePath2);
    
            // Compute the perceptual hashes of the images
            byte[] hash1 = ImageHelper.GetPerceptualHash(bitmap1);
            byte[] hash2 = ImageHelper.GetPerceptualHash(bitmap2);
    
            // Compute the Hamming distance between the hashes
            int distance = ImageHelper.HammingDistance(hash1, hash2);
    
            // Compare the Hamming distance to the threshold
            return (distance <= maxHammingDistance);
        }
    }
Designed by Tistory.