C# C语言中两幅位图图像之间的距离/相似性#
我发现以下代码取自:C# C语言中两幅位图图像之间的距离/相似性#,c#,image,bitmap,C#,Image,Bitmap,我发现以下代码取自: 使用系统; 使用系统图; 班级计划 { 静态void Main() { 位图img1=新位图(“Lenna50.jpg”); 位图img2=新位图(“Lenna100.jpg”); if(img1.Size!=img2.Size) { Console.Error.WriteLine(“图像大小不同”); 返回; } 浮动差=0; 对于(int y=0;y
使用系统;
使用系统图;
班级计划
{
静态void Main()
{
位图img1=新位图(“Lenna50.jpg”);
位图img2=新位图(“Lenna100.jpg”);
if(img1.Size!=img2.Size)
{
Console.Error.WriteLine(“图像大小不同”);
返回;
}
浮动差=0;
对于(int y=0;y
不幸的是,这真的很慢。有人知道计算两幅图像之间距离的更快方法吗?谢谢
提供更多的上下文。我正在做这样的事情:
package eu.veldsoft.ellipses.image.approximator;
import java.awt.image.BufferedImage;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
/**
* Compare to raster images by using Euclidean distance between the pixels but
* in probabilistic sampling on hierarchical image detailization.
*
* @author Todor Balabanov
*/
class HierarchicalProbabilisticImageComparator implements ImageComparator {
/** A pseudo-random number generator instance. */
private static final Random PRNG = new Random();
/**
* Euclidean distance color comparator instance.
*/
private static final ColorComparator EUCLIDEAN = new EuclideanColorComparator();
/** Recursive descent depth level. */
private int depthLevel = 1;
/**
* Size of the sample in percentages from the size of the population (from
* 0.0 to 1.0).
*/
private double samplePercent = 0.1;
/** A supportive array for the first image pixels. */
private int aPixels[] = null;
/** A supportive array for the second image pixels. */
private int bPixels[] = null;
/**
* Constructor without parameters for default members' values.
*/
public HierarchicalProbabilisticImageComparator() {
this(1, 0.1);
}
/**
* Constructor with all parameters.
*
* @param depthLevel
* Recursive descent depth level.
* @param samplePercent
* Size of the sample in percentages from the size of the
* population (from 0.0 to 1.0).
*/
public HierarchicalProbabilisticImageComparator(int depthLevel,
double samplePercent) {
super();
this.depthLevel = depthLevel;
this.samplePercent = samplePercent;
}
private double distance(int width, int level, int minX, int minY, int maxX,
int maxY) {
/*
* At the bottom of the recursive descent, distance is zero, and
* descending is canceled.
*/
if (level > depthLevel) {
return 0;
}
/* Rectangle's boundaries should be observed. */
if (maxX <= minX || maxY <= minY) {
return 0;
}
/*
* Sample size calculated according formula.
*
* https://www.surveymonkey.com/mp/sample-size-calculator/
*/
int sampleSize = (int) ((maxX - minX) * (maxY - minY) * samplePercent);
/* Generate unique indices of pixels with the size of the sample. */
Set<Integer> indices = new HashSet<Integer>();
while (indices.size() < sampleSize) {
int x = minX + PRNG.nextInt(maxX - minX + 1);
int y = minY + PRNG.nextInt(maxY - minY + 1);
indices.add(y * width + x);
}
/* The Euclidean distance of the randomly selected pixels. */
double sum = 0;
for (int index : indices) {
sum += EUCLIDEAN.distance(aPixels[index], bPixels[index]);
}
/* Do a recursive descent. */
return (sum / sampleSize) * level
+ distance(width, level + 1, minX, minY,
maxX - (maxX - minX) / 2, maxY - (maxY - minY) / 2)
+ distance(width, level + 1, maxX - (maxX - minX) / 2, minY,
maxX, maxY - (maxY - minY) / 2)
+ distance(width, level + 1, minX, maxY - (maxY - minY) / 2,
maxX - (maxX - minX) / 2, maxY)
+ distance(width, level + 1, maxX - (maxX - minX) / 2,
maxY - (maxY - minY) / 2, maxX, maxY);
}
/**
* {@inheritDoc}
*/
@Override
public double distance(BufferedImage a, BufferedImage b) {
if (a.getWidth() != b.getWidth()) {
throw new RuntimeException("Images width should be identical!");
}
if (a.getHeight() != b.getHeight()) {
throw new RuntimeException("Images height should be identical!");
}
aPixels = a.getRGB(0, 0, a.getWidth(), a.getHeight(), null, 0,
a.getWidth());
bPixels = b.getRGB(0, 0, b.getWidth(), b.getHeight(), null, 0,
b.getWidth());
/* Do a recursive calculation. */
return distance(Math.min(a.getWidth(), b.getWidth()), 1, 0, 0,
Math.min(a.getWidth() - 1, b.getWidth() - 1),
Math.min(a.getHeight() - 1, b.getHeight() - 1));
}
}
我进化SVG,然后将其转换为位图并与目标图像进行比较
刚看到aforgenet库-例如,请参见:
附言:
我开始用锁位重写上面的内容。下面的代码是我当前的尝试,但我有点卡住了。请注意,bmp1是“目标图片”,并没有真正改变-因此可以考虑复制/只需复制一次。位图bmp2被传入并与bmp1进行比较(有100个bmp2s)。最后,我想使用一些距离(例如,字节的欧几里德距离?)来确定bmp1和bmp2之间的相似性。任何关于这一点以及如何加速代码的建议都将不胜感激。谢谢
public double Compare(Bitmap bmp1, Bitmap bmp2)
{
BitmapData bitmapData1 = bmp1.LockBits(new Rectangle(0, 0, bmp1.Width, bmp1.Height), ImageLockMode.ReadWrite, bmp1.PixelFormat);
BitmapData bitmapData2 = bmp2.LockBits(new Rectangle(0, 0, bmp2.Width, bmp2.Height), ImageLockMode.ReadWrite, bmp2.PixelFormat);
IntPtr ptr1 = bitmapData1.Scan0;
int bytes1 = bitmapData1.Stride * bmp1.Height;
byte[] rgbValues1 = new byte[bytes1];
byte[] r1 = new byte[bytes1 / 3];
byte[] g1 = new byte[bytes1 / 3];
byte[] b1 = new byte[bytes1 / 3];
Marshal.Copy(ptr1, rgbValues1, 0, bytes1);
bmp1.UnlockBits(bitmapData1);
IntPtr ptr2 = bitmapData2.Scan0;
int bytes2 = bitmapData2.Stride * bmp2.Height;
byte[] rgbValues2 = new byte[bytes2];
byte[] r2 = new byte[bytes2 / 3];
byte[] g2 = new byte[bytes2 / 3];
byte[] b2 = new byte[bytes2 / 3];
Marshal.Copy(ptr2, rgbValues2, 0, bytes2);
bmp2.UnlockBits(bitmapData2);
int stride = bitmapData1.Stride;
for (int column = 0; column < bitmapData1.Height; column++)
{
for (int row = 0; row < bitmapData1.Width; row++)
{
//????
}
}
return 0;
}
公共双比较(位图bmp1、位图bmp2)
{
BitmapData bitmapData1=bmp1.LockBits(新矩形(0,0,bmp1.Width,bmp1.Height),ImageLockMode.ReadWrite,bmp1.PixelFormat);
BitmapData bitmapData2=bmp2.LockBits(新矩形(0,0,bmp2.Width,bmp2.Height),ImageLockMode.ReadWrite,bmp2.PixelFormat);
IntPtr ptr1=bitmapData1.Scan0;
int bytes1=bitmapData1.Stride*bmp1.Height;
字节[]rgbValues1=新字节[bytes1];
字节[]r1=新字节[bytes1/3];
字节[]g1=新字节[bytes1/3];
字节[]b1=新字节[bytes1/3];
封送处理副本(ptr1,rgbValues1,0,字节1);
bmp1.解锁位(bitmapData1);
IntPtr ptr2=bitmapData2.Scan0;
int bytes2=bitmapData2.Stride*bmp2.Height;
字节[]rgbValues2=新字节[bytes2];
字节[]r2=新字节[bytes2/3];
字节[]g2=新字节[bytes2/3];
字节[]b2=新字节[bytes2/3];
封送处理副本(ptr2,rgbValues2,0,bytes2);
bmp2.解锁位(bitmapData2);
int stride=bitmapData1.stride;
for(int column=0;column
缴费灵:
我(想我)取得了一些更大的进步。以下代码似乎有效:
using System.Drawing;
using System.Drawing.Imaging;
using Color = System.Drawing.Color;
namespace ClassLibrary1
{
public unsafe class BitmapComparer : IBitmapComparer
{
private readonly Color[] _targetBitmapColors;
private readonly int _width;
private readonly int _height;
private readonly int _maxPointerLength;
private readonly PixelFormat _pixelFormat;
public BitmapComparer(Bitmap targetBitmap)
{
_width = targetBitmap.Width;
_height = targetBitmap.Height;
_maxPointerLength = _width * _height;
_pixelFormat = targetBitmap.PixelFormat;
_targetBitmapColors = new Color[_maxPointerLength];
var bData = targetBitmap.LockBits(new Rectangle(0, 0, _width, _height), ImageLockMode.ReadWrite, _pixelFormat);
var scan0 = (byte*) bData.Scan0.ToPointer();
for (var i = 0; i < _maxPointerLength; i += 4)
{
_targetBitmapColors[i] = Color.FromArgb(scan0[i + 2], scan0[i + 1], scan0[i + 0]);
}
targetBitmap.UnlockBits(bData);
}
// https://rogerjohansson.blog/2008/12/09/genetic-programming-mona-lisa-faq/
public double Compare(Bitmap bitmapToCompareWith)
{
var bData = bitmapToCompareWith.LockBits(new Rectangle(0, 0, _width, _height), ImageLockMode.ReadWrite, _pixelFormat);
var scan0 = (byte*) bData.Scan0.ToPointer();
double distance = 0;
for (var i = 0; i < _maxPointerLength; i += 4)
{
distance +=
( ((_targetBitmapColors[i].R - scan0[i + 2]) * (_targetBitmapColors[i].R - scan0[i + 2]))
+ ((_targetBitmapColors[i].G - scan0[i + 1]) * (_targetBitmapColors[i].G - scan0[i + 1]))
+ ((_targetBitmapColors[i].B - scan0[i + 0]) * (_targetBitmapColors[i].B - scan0[i + 0])));
}
bitmapToCompareWith.UnlockBits(bData);
return distance;
}
}
}
使用系统图;
使用系统、绘图、成像;
使用颜色=System.Drawing.Color;
命名空间类库1
{
公共不安全类位图比较器:IBitMacComparer
{
私有只读颜色[]_targetBitMapColor;
私有只读整数宽度;
专用只读int_高度;
私有只读int_maxPointerLength;
私有只读像素格式_PixelFormat;
公共位图比较器(位图目标位图)
{
_宽度=targetBitmap.width;
_高度=targetBitmap.height;
_maxPointerLength=_width*_height;
_pixelFormat=targetBitmap.pixelFormat;
_targetBitmapColors=新颜色[_maxPointerLength];
var bData=targetBitmap.LockBits(新矩形(0,0,0,u宽度,\u高度)、ImageLockMode.ReadWrite、\u像素格式);
var scan0=(字节*)bData.scan0.ToPointer();
对于(变量i=0;i<_maxPointerLength;i+=4)
{
_targetBitmapColors[i]=Color.FromArgb(扫描0[i+2],扫描0[i+1],扫描0[i+0]);
}
targetBitmap.UnlockBits(bData);
}
// https://rogerjohansson.blog/2008/12/09/genetic-programming-mona-lisa-faq/
公共双比较(位图位图位图比较)
{
var bData=bitmapToCompareWith.LockBits(新矩形(0,0,_宽度,_高度),ImageLockMode.ReadWrite,_像素格式);
var scan0=(字节*)bData.scan0.ToPointer();
双倍距离=0;
对于(变量i=0;i<_maxPointerLength;i+=4)
{
距离+=
((_targetBitmapColor[i].R-scan0[i+2])*(_targetBitmapColor[i].R-scan0[i+2]))
+((_targetBitMapColor[i].G-scan0[i+1])*(_targetBitMapColor[i].G-scan0[i+1]))
+((_targetBitmapColors[i].B-scan0[i+0])*(_targetBitmapColors[i].B-scan0[i+0]);
}
BitMapToCompare.UnlockBits(bData);
返回距离;
}
}
}
正如其他人所指出的,您可以使用位图.LockBits
并使用指针而不是GetPixel
。以下运行速度比原始方法快约200倍:
static float CalculateDifference(Bitmap bitmap1, Bitmap bitmap2)
{
if (bitmap1.Size != bitmap2.Size)
{
return -1;
}
var rectangle = new Rectangle(0, 0, bitmap1.Width, bitmap1.Height);
BitmapData bitmapData1 = bitmap1.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap1.PixelFormat);
BitmapData bitmapData2 = bitmap2.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap2.PixelFormat);
float diff = 0;
var byteCount = rectangle.Width * rectangle.Height * 3;
unsafe
{
// scan to first byte in bitmaps
byte* pointer1 = (byte*)bitmapData1.Scan0.ToPointer();
byte* pointer2 = (byte*)bitmapData2.Scan0.ToPointer();
for (int x = 0; x < byteCount; x++)
{
diff += (float)Math.Abs(*pointer1 - *pointer2) / 255;
pointer1++;
pointer2++;
}
}
bitmap1.UnlockBits(bitmapData1);
bitmap2.UnlockBits(bitmapData2);
return 100 * diff / byteCount;
}
静态浮点计算差异(位图bitmap1、位图bitmap2)
{
if(bitmap1.Size!=bitmap2.Size)
{
返回-1;
}
var rectangle=新矩形(0,0,bitmap1.Width,bitmap1.Height);
BitmapData bitmapData1=bitmap1.LockBits(矩形,ImageLockMode.ReadOnly,bitmap1.PixelFormat);
BitmapData bitmapData2=bitmap2.LockBits(矩形,ImageLockMode.ReadOnly,bitmap2.PixelFormat);
浮动差=0;
var byteCount=rectangle.Width*rectangle.Height*3;
不安全的
{
//扫描到位图中的第一个字节
byte*pointer1=(byte*)bitmapData1.Scan0.ToPointer();
字节*指针2=(字节*)位图数据2.Scan0.ToP
package eu.veldsoft.ellipses.image.approximator;
import java.awt.image.BufferedImage;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
/**
* Compare to raster images by using Euclidean distance between the pixels but
* in probabilistic sampling on hierarchical image detailization.
*
* @author Todor Balabanov
*/
class HierarchicalProbabilisticImageComparator implements ImageComparator {
/** A pseudo-random number generator instance. */
private static final Random PRNG = new Random();
/**
* Euclidean distance color comparator instance.
*/
private static final ColorComparator EUCLIDEAN = new EuclideanColorComparator();
/** Recursive descent depth level. */
private int depthLevel = 1;
/**
* Size of the sample in percentages from the size of the population (from
* 0.0 to 1.0).
*/
private double samplePercent = 0.1;
/** A supportive array for the first image pixels. */
private int aPixels[] = null;
/** A supportive array for the second image pixels. */
private int bPixels[] = null;
/**
* Constructor without parameters for default members' values.
*/
public HierarchicalProbabilisticImageComparator() {
this(1, 0.1);
}
/**
* Constructor with all parameters.
*
* @param depthLevel
* Recursive descent depth level.
* @param samplePercent
* Size of the sample in percentages from the size of the
* population (from 0.0 to 1.0).
*/
public HierarchicalProbabilisticImageComparator(int depthLevel,
double samplePercent) {
super();
this.depthLevel = depthLevel;
this.samplePercent = samplePercent;
}
private double distance(int width, int level, int minX, int minY, int maxX,
int maxY) {
/*
* At the bottom of the recursive descent, distance is zero, and
* descending is canceled.
*/
if (level > depthLevel) {
return 0;
}
/* Rectangle's boundaries should be observed. */
if (maxX <= minX || maxY <= minY) {
return 0;
}
/*
* Sample size calculated according formula.
*
* https://www.surveymonkey.com/mp/sample-size-calculator/
*/
int sampleSize = (int) ((maxX - minX) * (maxY - minY) * samplePercent);
/* Generate unique indices of pixels with the size of the sample. */
Set<Integer> indices = new HashSet<Integer>();
while (indices.size() < sampleSize) {
int x = minX + PRNG.nextInt(maxX - minX + 1);
int y = minY + PRNG.nextInt(maxY - minY + 1);
indices.add(y * width + x);
}
/* The Euclidean distance of the randomly selected pixels. */
double sum = 0;
for (int index : indices) {
sum += EUCLIDEAN.distance(aPixels[index], bPixels[index]);
}
/* Do a recursive descent. */
return (sum / sampleSize) * level
+ distance(width, level + 1, minX, minY,
maxX - (maxX - minX) / 2, maxY - (maxY - minY) / 2)
+ distance(width, level + 1, maxX - (maxX - minX) / 2, minY,
maxX, maxY - (maxY - minY) / 2)
+ distance(width, level + 1, minX, maxY - (maxY - minY) / 2,
maxX - (maxX - minX) / 2, maxY)
+ distance(width, level + 1, maxX - (maxX - minX) / 2,
maxY - (maxY - minY) / 2, maxX, maxY);
}
/**
* {@inheritDoc}
*/
@Override
public double distance(BufferedImage a, BufferedImage b) {
if (a.getWidth() != b.getWidth()) {
throw new RuntimeException("Images width should be identical!");
}
if (a.getHeight() != b.getHeight()) {
throw new RuntimeException("Images height should be identical!");
}
aPixels = a.getRGB(0, 0, a.getWidth(), a.getHeight(), null, 0,
a.getWidth());
bPixels = b.getRGB(0, 0, b.getWidth(), b.getHeight(), null, 0,
b.getWidth());
/* Do a recursive calculation. */
return distance(Math.min(a.getWidth(), b.getWidth()), 1, 0, 0,
Math.min(a.getWidth() - 1, b.getWidth() - 1),
Math.min(a.getHeight() - 1, b.getHeight() - 1));
}
}