큰 이미지에서 작은 이미지 좌표를

큰 이미지에서 작은 이미지 좌표를 찾기 위한 가능한 알고리즘은 다음과 같습니다.

  1. 크기보다 큰 크기의 작은 이미지 주위에 검색 표시줄을 정의합니다.

    작은 사진들.
  2. 검색 표시줄을 더 작은 창의 그리드로 나눕니다.

    이 작은 창의 크기는 작은 이미지의 크기보다 약간 커야 합니다.

  3. 각각의 작은 창에 대해 작은 이미지와 해당 영역 간의 유사성 값을 계산합니다.

    큰 그림. 유사성을 측정할 수 있는 한 가지 방법은 두 이미지의 해당 픽셀 간의 차이 제곱합(SSD)입니다.

  4. 유사도 값이 가장 높은 창을 찾습니다.

    이것은 큰 이미지에서 작은 이미지의 위치일 가능성이 큽니다.

  5. 에서 찾은 위치 주변의 작은 창에 대한 유사성 값을 계산하여 작은 이미지의 위치를 ​​미세 조정합니다.

    4단계. 이는 경사 하강법 또는 Lucas-Kanade 광학 흐름과 같은 기술을 사용하여 수행할 수 있습니다.

  6. 큰 이미지에서 작은 이미지의 최종 위치를 반환합니다.

이 알고리즘은 유사성 점수의 계산 속도를 높이기 위해 이미지 피라미드 및 캐싱과 같은 기술을 사용하여 더욱 최적화될 수 있습니다.

또한 더 큰 이미지 내에서 더 작은 이미지의 여러 인스턴스를 찾아야 하는 경우 슬라이딩 윈도우 방식이나 SIFT 또는 SURF 기능 감지와 같은 고급 기술을 사용하도록 알고리즘을 확장할 수 있습니다.

using System;
using System.Drawing;

public class ImageFinder {
    private Bitmap largeImage;
    private Bitmap smallImage;
    private int searchWindowRadius;
    private int gridSpacing;
    
    public ImageFinder(Bitmap largeImage, Bitmap smallImage, int searchWindowRadius, int gridSpacing) {
        this.largeImage = largeImage;
        this.smallImage = smallImage;
        this.searchWindowRadius = searchWindowRadius;
        this.gridSpacing = gridSpacing;
    }
    
    public Point FindSmallImage() {
        // Define the search window around the small image
        int searchWindowWidth = 2 * searchWindowRadius + smallImage.Width;
        int searchWindowHeight = 2 * searchWindowRadius + smallImage.Height;
        Rectangle searchWindow = new Rectangle(Point.Empty, new Size(searchWindowWidth, searchWindowHeight));
        
        // Divide the search window into a grid of smaller windows
        int numGridCols = (searchWindow.Width - smallImage.Width) / gridSpacing + 1;
        int numGridRows = (searchWindow.Height - smallImage.Height) / gridSpacing + 1;
        Rectangle() gridWindows = new Rectangle(numGridCols * numGridRows);
        int i = 0;
        for (int y = searchWindow.Top; y <= searchWindow.Bottom - smallImage.Height; y += gridSpacing) {
            for (int x = searchWindow.Left; x <= searchWindow.Right - smallImage.Width; x += gridSpacing) {
                gridWindows(i++) = new Rectangle(x, y, smallImage.Width, smallImage.Height);
            }
        }
        
        // Compute similarity scores for each grid window
        double() scores = new double(gridWindows.Length);
        for (i = 0; i < gridWindows.Length; i++) {
            scores(i) = ComputeSimilarityScore(gridWindows(i));
        }
        
        // Find the grid window with the highest similarity score
        int bestIndex = 0;
        double bestScore = scores(0);
        for (i = 1; i < scores.Length; i++) {
            if (scores(i) > bestScore) {
                bestIndex = i;
                bestScore = scores(i);
            }
        }
        
        // Refine the location of the small image using gradient descent
        Rectangle bestWindow = gridWindows(bestIndex);
        Point bestLocation = new Point(bestWindow.Left + smallImage.Width / 2, bestWindow.Top + smallImage.Height / 2);
        Point refinedLocation = RefineLocation(bestLocation);
        
        return refinedLocation;
    }
    
    private double ComputeSimilarityScore(Rectangle window) {
        double score = 0.0;
        
        for (int y = 0; y < smallImage.Height; y++) {
            for (int x = 0; x < smallImage.Width; x++) {
                Color pixel1 = smallImage.GetPixel(x, y);
                Color pixel2 = largeImage.GetPixel(window.Left + x, window.Top + y);
                double diffR = pixel1.R - pixel2.R;
                double diffG = pixel1.G - pixel2.G;
                double diffB = pixel1.B - pixel2.B;
                score += diffR * diffR + diffG * diffG + diffB * diffB;
            }
        }
        
        return score;
    }
    
    private Point RefineLocation(Point initialLocation) {
        const double stepSize = 1.0;
        const int maxIterations = 50;
        const double tolerance = 1e-3;
        
        Point currentLocation = initialLocation;
        double currentScore = ComputeSimilarityScore(new Rectangle(currentLocation.X - searchWindowRadius, currentLocation.Y - searchWindowRadius, smallImage.Width + 2 * searchWindowRadius, smallImage.Height + 2 * searchWindowRadius));
		
		for (int i = 0; i < maxIterations; i++) {
        Point gradient = ComputeGradient(currentLocation);
        Point newLocation = new Point(currentLocation.X + (int)(stepSize * gradient.X), currentLocation.Y + (int)(stepSize * gradient.Y));
        double newScore = ComputeSimilarityScore(new Rectangle(newLocation.X - searchWindowRadius, newLocation.Y - searchWindowRadius, smallImage.Width + 2 * searchWindowRadius, smallImage.Height + 2 * searchWindowRadius));
        
			if (newScore >= currentScore) {
				currentLocation = newLocation;
				currentScore = newScore;
			}
			else {
				stepSize /= 2.0;
			}
			
			if (stepSize < tolerance) {
				break;
			}
		}
		return currentLocation;
	}

private Point ComputeGradient(Point location) {
    int dx = 0;
    int dy = 0;
    
    for (int y = location.Y - searchWindowRadius; y <= location.Y + searchWindowRadius; y++) {
        for (int x = location.X - searchWindowRadius; x <= location.X + searchWindowRadius; x++) {
            Color pixel1 = smallImage.GetPixel(x - location.X + searchWindowRadius, y - location.Y + searchWindowRadius);
            Color pixel2 = largeImage.GetPixel(x, y);
            double diffR = pixel1.R - pixel2.R;
            double diffG = pixel1.G - pixel2.G;
            double diffB = pixel1.B - pixel2.B;
            dx += (int)(2 * diffR * (x - location.X) + 2 * diffG * (x - location.X) + 2 * diffB * (x - location.X));
            dy += (int)(2 * diffR * (y - location.Y) + 2 * diffG * (y - location.Y) + 2 * diffB * (y - location.Y));
        }
    }
    
    return new Point(dx, dy);
}