큰 이미지에서 작은 이미지 좌표를 찾기 위한 가능한 알고리즘은 다음과 같습니다.
- 크기보다 큰 크기의 작은 이미지 주위에 검색 표시줄을 정의합니다.
작은 사진들. - 검색 표시줄을 더 작은 창의 그리드로 나눕니다.
이 작은 창의 크기는 작은 이미지의 크기보다 약간 커야 합니다. - 각각의 작은 창에 대해 작은 이미지와 해당 영역 간의 유사성 값을 계산합니다.
큰 그림. 유사성을 측정할 수 있는 한 가지 방법은 두 이미지의 해당 픽셀 간의 차이 제곱합(SSD)입니다. - 유사도 값이 가장 높은 창을 찾습니다.
이것은 큰 이미지에서 작은 이미지의 위치일 가능성이 큽니다. - 에서 찾은 위치 주변의 작은 창에 대한 유사성 값을 계산하여 작은 이미지의 위치를 미세 조정합니다.
4단계. 이는 경사 하강법 또는 Lucas-Kanade 광학 흐름과 같은 기술을 사용하여 수행할 수 있습니다. - 큰 이미지에서 작은 이미지의 최종 위치를 반환합니다.
이 알고리즘은 유사성 점수의 계산 속도를 높이기 위해 이미지 피라미드 및 캐싱과 같은 기술을 사용하여 더욱 최적화될 수 있습니다.
또한 더 큰 이미지 내에서 더 작은 이미지의 여러 인스턴스를 찾아야 하는 경우 슬라이딩 윈도우 방식이나 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);
}