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));
    }
}