728x90
반응형
728x170
[TestCommon 프로젝트]
▶ ComparableImage.cs
using System;
using System.Drawing;
using System.IO;
namespace TestCommon
{
/// <summary>
/// 비교 가능 이미지
/// </summary>
public class ComparableImage
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 파일 정보
/// </summary>
private readonly FileInfo fileInfo;
/// <summary>
/// RGB 프로젝션
/// </summary>
private readonly RGBProjection rgbProjection;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 파일 정보 - FileInfo
/// <summary>
/// 파일 정보
/// </summary>
public FileInfo FileInfo
{
get
{
return this.fileInfo;
}
}
#endregion
#region RGB 프로젝션 - RGBProjection
/// <summary>
/// RGB 프로젝션
/// </summary>
public RGBProjection RGBProjection
{
get
{
return this.rgbProjection;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - ComparableImage(fileInfo)
/// <summary>
/// 생성자
/// </summary>
/// <param name="fileInfo">파일 정보</param>
public ComparableImage(FileInfo fileInfo)
{
if(fileInfo == null)
{
throw new ArgumentNullException("fileInfo");
}
if(!fileInfo.Exists)
{
throw new FileNotFoundException();
}
this.fileInfo = fileInfo;
using(Bitmap bitmap = ImageHelper.ResizeBitmap(new Bitmap(fileInfo.FullName), 100, 100))
{
this.rgbProjection = new RGBProjection(ImageHelper.GetRGBProjectionArray(bitmap));
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 유사도 계산하기 - CalculateSimilarity(source)
/// <summary>
/// 유사도 계산하기
/// </summary>
/// <param name="source">소스 비교 가능 이미지</param>
/// <returns>유사도</returns>
public double CalculateSimilarity(ComparableImage source)
{
return this.rgbProjection.CalculateSimilarity(source.rgbProjection);
}
#endregion
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return this.fileInfo.Name;
}
#endregion
}
}
728x90
▶ ImageHelper.cs
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
namespace TestCommon
{
/// <summary>
/// 이미지 헬퍼
/// </summary>
public static class ImageHelper
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 비트맵 크기 조정하기 - ResizeBitmap(bitmap, width, height)
/// <summary>
/// 비트맵 크기 조정하기
/// </summary>
/// <param name="bitmap">비트맵</param>
/// <param name="width">너비</param>
/// <param name="height">높이</param>
/// <returns>비트맵</returns>
public static Bitmap ResizeBitmap(Bitmap bitmap, int width, int height)
{
Bitmap result = new Bitmap(width, height);
using(Graphics graphic = Graphics.FromImage((Image)result))
{
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.DrawImage(bitmap, 0, 0, width - 1, height - 1);
}
return result;
}
#endregion
#region RGB 프로젝션 배열 구하기 - GetRGBProjectionArray(bitmap)
/// <summary>
/// RGB 프로젝션 배열 구하기
/// </summary>
/// <param name="bitmap">비트맵</param>
/// <returns>RGB 프로젝션 배열</returns>
public static double[][] GetRGBProjectionArray(Bitmap bitmap)
{
int width = bitmap.Width - 1;
int height = bitmap.Height - 1;
double[] horizontalProjectionArray = new double[width ];
double[] verticalProjectionArray = new double[height];
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
unsafe
{
byte* imagePointer = (byte*)bitmapData.Scan0;
for(int y = 0; y < height; y++)
{
for(int x = 0; x < width; x++)
{
byte blue = imagePointer[0];
byte green = imagePointer[1];
byte red = imagePointer[2];
int luminosity = (byte)(((0.2126 * red) + (0.7152 * green)) + (0.0722 * blue));
horizontalProjectionArray[x] += luminosity;
verticalProjectionArray[y] += luminosity;
imagePointer += 4;
}
imagePointer += bitmapData.Stride - (bitmapData.Width * 4);
}
}
MaximizeScale(ref horizontalProjectionArray, height);
MaximizeScale(ref verticalProjectionArray , width );
double[][] projectionArray = new[] { horizontalProjectionArray, verticalProjectionArray };
bitmap.UnlockBits(bitmapData);
return projectionArray;
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Private
#region 스케일 최대화 하기 - MaximizeScale(projectionArray, elementMaximumValue)
/// <summary>
/// 스케일 최대화 하기
/// </summary>
/// <param name="projectionArray">프로젝션 배열</param>
/// <param name="elementMaximumValue">요소 최대 값</param>
private static void MaximizeScale(ref double[] projectionArray, double elementMaximumValue)
{
double minimumValue = double.MaxValue;
double maximumValue = double.MinValue;
for(var i = 0; i < projectionArray.Length; i++)
{
if(projectionArray[i] > 0)
{
projectionArray[i] = projectionArray[i] / elementMaximumValue;
}
if(projectionArray[i] < minimumValue)
{
minimumValue = projectionArray[i];
}
if(projectionArray[i] > maximumValue)
{
maximumValue = projectionArray[i];
}
}
if(maximumValue == 0)
{
return;
}
for(var i = 0; i < projectionArray.Length; i++)
{
if(maximumValue == 255)
{
projectionArray[i] = 1;
}
else
{
projectionArray[i] = (projectionArray[i] - minimumValue) / (maximumValue - minimumValue);
}
}
}
#endregion
}
}
300x250
▶ RGBProjection.cs
using System;
using System.Collections.Generic;
using System.Linq;
namespace TestCommon
{
/// <summary>
/// RGB 프로젝션
/// </summary>
public class RGBProjection
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 수평 프로젝션 배열
/// </summary>
private readonly double[] horizontalProjectionArray;
/// <summary>
/// 수직 프로젝션 배열
/// </summary>
private readonly double[] verticalProjectionArray;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 수평 프로젝션 배열 - HorizontalProjectionArray
/// <summary>
/// 수평 프로젝션 배열
/// </summary>
public double[] HorizontalProjectionArray
{
get
{
return horizontalProjectionArray;
}
}
#endregion
#region 수직 프로젝션 배열 - VerticalProjectionArray
/// <summary>
/// 수직 프로젝션 배열
/// </summary>
public double[] VerticalProjectionArray
{
get
{
return verticalProjectionArray;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - RGBProjection(horizontalProjectionArray, verticalProjectionArray)
/// <summary>
/// 생성자
/// </summary>
/// <param name="horizontalProjectionArray">수평 프로젝션 배열</param>
/// <param name="verticalProjectionArray">수직 프로젝션 배열</param>
public RGBProjection(double[] horizontalProjectionArray, double[] verticalProjectionArray)
{
this.horizontalProjectionArray = horizontalProjectionArray;
this.verticalProjectionArray = verticalProjectionArray;
}
#endregion
#region 생성자 - RGBProjection(projectionArray)
/// <summary>
/// 생성자
/// </summary>
/// <param name="projectionArray">프로젝션 배열</param>
public RGBProjection(double[][] projectionArray) : this(projectionArray[0], projectionArray[1])
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 유사도 계산하기 - CalculateSimilarity(source)
/// <summary>
/// 유사도 계산하기
/// </summary>
/// <param name="source">소스 RGB 프로젝션</param>
/// <returns>유사도</returns>
public double CalculateSimilarity(RGBProjection source)
{
double horizontalSimilarity = CalculateProjectionSimilarity(horizontalProjectionArray, source.horizontalProjectionArray);
double verticalSimilarity = CalculateProjectionSimilarity(verticalProjectionArray , source.verticalProjectionArray );
return Math.Max(horizontalSimilarity, verticalSimilarity);
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 프로젝션 유사도 계산하기 - CalculateProjectionSimilarity(sourceProjectionArray, targetProjectionArray)
/// <summary>
/// 프로젝션 유사도 계산하기
/// </summary>
/// <param name="sourceProjectionArray">소스 프로젝션 배열</param>
/// <param name="targetProjectionArray">타겟 프로젝션 배열</param>
/// <returns>프로젝션 유사도</returns>
/// <remarks>유사도 : 0 ~ 1 사이의 값을 반환한다.</remarks>
private static double CalculateProjectionSimilarity(double[] sourceProjectionArray, double[] targetProjectionArray)
{
if(sourceProjectionArray.Length != targetProjectionArray.Length)
{
throw new ArgumentException();
}
Dictionary<double, int> frequencyDictionary = new Dictionary<double, int>();
for(int i = 0; i < sourceProjectionArray.Length; i++)
{
double difference = sourceProjectionArray[i] - targetProjectionArray[i];
difference = Math.Round(difference, 2);
difference = Math.Abs(difference);
if(frequencyDictionary.ContainsKey(difference))
{
frequencyDictionary[difference] = frequencyDictionary[difference] + 1;
}
else
{
frequencyDictionary.Add(difference, 1);
}
}
double deviation = frequencyDictionary.Sum(value => (value.Key * value.Value));
deviation /= sourceProjectionArray.Length;
deviation = (0.5 - deviation) * 2;
return deviation;
}
#endregion
}
}
▶ SimilarityImage.cs
using System;
using System.Collections.Generic;
namespace TestCommon
{
/// <summary>
/// 유사도 이미지
/// </summary>
public class SimilarityImage : IComparer<SimilarityImage>, IComparable
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 소스 비교 가능 이미지
/// </summary>
private readonly ComparableImage source;
/// <summary>
/// 타겟 비교 가능 이미지
/// </summary>
private readonly ComparableImage target;
/// <summary>
/// 유사도
/// </summary>
private readonly double similarity;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 소스 비교 가능 이미지 - Source
/// <summary>
/// 소스 비교 가능 이미지
/// </summary>
public ComparableImage Source
{
get
{
return this.source;
}
}
#endregion
#region 타겟 비교 가능 이미지 - Target
/// <summary>
/// 타겟 비교 가능 이미지
/// </summary>
public ComparableImage Target
{
get
{
return this.target;
}
}
#endregion
#region 유사도 - Similarity
/// <summary>
/// 유사도
/// </summary>
public double Similarity
{
get
{
return Math.Round(this.similarity * 100, 1);
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - SimilarityImage(source, target, similarity)
/// <summary>
/// 생성자
/// </summary>
/// <param name="source">소스 비교 가능 이미지</param>
/// <param name="target">타겟 비교 가능 이미지</param>
/// <param name="similarity">유사도</param>
public SimilarityImage(ComparableImage source, ComparableImage target, double similarity)
{
this.source = source;
this.target = target;
this.similarity = similarity;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region == 연산자 재정의하기 - ==(sourceImage, targetImage)
/// <summary>
/// == 연산자 재정의하기
/// </summary>
/// <param name="sourceImage">소스 유사도 이미지</param>
/// <param name="targetImage">타겟 유사도 이미지</param>
/// <returns>처리 결과</returns>
public static int operator ==(SimilarityImage sourceImage, SimilarityImage targetImage)
{
return sourceImage.CompareTo(targetImage);
}
#endregion
#region != 연산자 재정의하기 - !=(sourceImage, targetImage)
/// <summary>
/// != 연산자 재정의하기
/// </summary>
/// <param name="sourceImage">소스 유사도 이미지</param>
/// <param name="targetImage">타겟 유사도 이미지</param>
/// <returns>처리 결과</returns>
public static int operator !=(SimilarityImage sourceImage, SimilarityImage targetImage)
{
return sourceImage.CompareTo(targetImage);
}
#endregion
#region < 연산자 재정의하기 - <(sourceImage, targetImage)
/// <summary>
/// < 연산자 재정의하기
/// </summary>
/// <param name="sourceImage">소스 유사도 이미지</param>
/// <param name="targetImage">타겟 유사도 이미지</param>
/// <returns>처리 결과</returns>
public static int operator <(SimilarityImage sourceImage, SimilarityImage targetImage)
{
return sourceImage.CompareTo(targetImage);
}
#endregion
#region > 연산자 재정의하기 - >(sourceImage, targetImage)
/// <summary>
/// > 연산자 재정의하기
/// </summary>
/// <param name="sourceImage">소스 유사도 이미지</param>
/// <param name="targetImage">타겟 유사도 이미지</param>
/// <returns>처리 결과</returns>
public static int operator >(SimilarityImage sourceImage, SimilarityImage targetImage)
{
return sourceImage.CompareTo(targetImage);
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Public
#region (IComparer<T>) 비교하기 - Compare(x, y)
/// <summary>
/// 비교하기
/// </summary>
/// <param name="x">유사도 이미지 X</param>
/// <param name="y">유사도 이미지 Y</param>
/// <returns>비교 결과</returns>
public int Compare(SimilarityImage x, SimilarityImage y)
{
return x.similarity.CompareTo(y.similarity);
}
#endregion
#region (IComparable) 비교하기 - CompareTo(sourceObject)
/// <summary>
/// 비교하기
/// </summary>
/// <param name="sourceObject">소스 객체</param>
/// <returns>비교 결과</returns>
public int CompareTo(object sourceObject)
{
SimilarityImage similarityImage = (SimilarityImage)sourceObject;
return this.Compare(this, similarityImage);
}
#endregion
#region 동일 여부 구하기 - Equals(sourceObject)
/// <summary>
/// 동일 여부 구하기
/// </summary>
/// <param name="sourceObject">소스 객체</param>
/// <returns>동일 여부</returns>
public override bool Equals(object sourceObject)
{
if(sourceObject == null || GetType() != sourceObject.GetType())
{
return false;
}
SimilarityImage similarityImage = sourceObject as SimilarityImage;
bool isSame = Source.FileInfo.FullName.Equals(similarityImage.Source.FileInfo.FullName, StringComparison.InvariantCultureIgnoreCase);
if(!isSame)
{
return false;
}
isSame = Target.FileInfo.FullName.Equals(similarityImage.Target.FileInfo.FullName, StringComparison.InvariantCultureIgnoreCase);
if(!isSame)
{
return false;
}
return true;
}
#endregion
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return string.Format("{0}, {1} --> {2}", this.source.FileInfo.Name, this.target.FileInfo.Name, this.similarity);
}
#endregion
#region 해시 코드 구하기 - GetHashCode()
/// <summary>
/// 해시 코드 구하기
/// </summary>
/// <returns>해시 코드</returns>
public override int GetHashCode()
{
return string.Format("{0};{1}", this.source.FileInfo.FullName, this.target.FileInfo.FullName).GetHashCode();
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WinForm' 카테고리의 다른 글
[C#/WINFORM] Application 클래스 : DoEvents 정적 메소드를 사용해 시간 지연하기 (0) | 2018.10.22 |
---|---|
[C#/WINFORM] ProgressBar 클래스 : 진행바 상태 설정하기 (0) | 2018.10.22 |
[C#/WINFORM] 디자인 모드 여부 구하기 (0) | 2018.10.14 |
[C#/WINFORM] 디자인 모드 여부 구하기 (0) | 2018.10.14 |
[C#/WINFORM] YOLO 이미지 객체 인식하기 (0) | 2018.09.22 |
[C#/WINFORM] 텐서플로우를 사용해 물체 인식하기 (0) | 2018.09.01 |
[C#/WINFORM] Cursor 클래스 : 이미지 커서 구하기 (0) | 2018.09.01 |
[C#/WINFORM] DataGridView 클래스 : RowPostPaint 이벤트를 사용해 행 번호 표시하기 (0) | 2018.09.01 |
[C#/WINFORM] DataGridView 클래스 : 마우스를 사용해 항목 순서 변경하기 (0) | 2018.09.01 |
[C#/WINFORM] 텐서플로우를 사용해 물체 인식하기 (0) | 2018.08.29 |
댓글을 달아 주세요