在C#中查找大图中的Subimage [英] Find Subimage in larger image in C#

查看:125
本文介绍了在C#中查找大图中的Subimage的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想编写一个获得2个位图(小图像和大图像)的函数。
它应该搜索大图像中小图像的位置。然后它应该返回子图像所在的(X / Y)点。

I want to program a function that gets 2 Bitmaps (small image and large image). It should search the position of the small one in the large image. Then it should return the (X/Y) Point where the subimage is located at.

我已经找到了一堆解决方案,但都是用Java编写的,例如:在较大的图像中查找已知的子图像
所以我尝试用C#重新编程它们,但我总是失败,因为代码不是真正的Java。方法Image.getPixel(x,y)在那里不存在,我真的不知道阈值应该是什么。

I have already found a bunch of solutions, but all were written in Java, for example this one: Find known sub image in larger image So I tried to reprogram them in C#, but I always failed, because the code is not real Java. The method Image.getPixel(x, y) does not exist there and I don't really know, what the threshold should be.

推荐答案

你去吧。此函数返回在larg图像中找到的所有位置,因为小图像也可以多次包含在大图像中。如果需要,可以重写函数unsafe以获得更高的性能。

There you go. This function return all locations found in the larg image, because small image could also multiple times contained in the large one. If you want, you can rewrite the function unsafe for more performance.

public static List<Point> GetSubPositions(Bitmap main, Bitmap sub) {
    List<Point> possiblepos = new List<Point>();

    int mainwidth = main.Width;
    int mainheight = main.Height;

    int subwidth = sub.Width;
    int subheight = sub.Height;

    int movewidth = mainwidth - subwidth;
    int moveheight = mainheight - subheight;

    BitmapData bmMainData = main.LockBits(new Rectangle(0, 0, mainwidth, mainheight), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
    BitmapData bmSubData = sub.LockBits(new Rectangle(0, 0, subwidth, subheight), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

    int bytesMain = Math.Abs(bmMainData.Stride) * mainheight;
    int strideMain = bmMainData.Stride;
    System.IntPtr Scan0Main = bmMainData.Scan0;
    byte[] dataMain = new byte[bytesMain];
    System.Runtime.InteropServices.Marshal.Copy(Scan0Main, dataMain, 0, bytesMain);

    int bytesSub = Math.Abs(bmSubData.Stride) * subheight;
    int strideSub = bmSubData.Stride;
    System.IntPtr Scan0Sub = bmSubData.Scan0;
    byte[] dataSub = new byte[bytesSub];
    System.Runtime.InteropServices.Marshal.Copy(Scan0Sub, dataSub, 0, bytesSub);

    for (int y = 0; y < moveheight; ++y) {
        for (int x = 0; x < movewidth; ++x) {
            MyColor curcolor = GetColor(x, y, strideMain, dataMain);

            foreach (var item in possiblepos.ToArray()) {
                int xsub = x - item.X;
                int ysub = y - item.Y;
                if (xsub >= subwidth || ysub >= subheight || xsub < 0)
                    continue;

                MyColor subcolor = GetColor(xsub, ysub, strideSub, dataSub);

                if (!curcolor.Equals(subcolor)) {
                    possiblepos.Remove(item);
                }
            }

            if (curcolor.Equals(GetColor(0, 0, strideSub, dataSub)))
                possiblepos.Add(new Point(x, y));
        }
    }

    System.Runtime.InteropServices.Marshal.Copy(dataSub, 0, Scan0Sub, bytesSub);
    sub.UnlockBits(bmSubData);

    System.Runtime.InteropServices.Marshal.Copy(dataMain, 0, Scan0Main, bytesMain);
    main.UnlockBits(bmMainData);

    return possiblepos;
}

private static MyColor GetColor(Point point, int stride, byte[] data) {
    return GetColor(point.X, point.Y, stride, data);
}

private static MyColor GetColor(int x, int y, int stride, byte[] data) {
    int pos = y * stride + x * 4;
    byte a = data[pos + 3];
    byte r = data[pos + 2];
    byte g = data[pos + 1];
    byte b = data[pos + 0];
    return MyColor.FromARGB(a, r, g, b);
}

struct MyColor {
    byte A;
    byte R;
    byte G;
    byte B;

    public static MyColor FromARGB(byte a, byte r, byte g, byte b) {
        MyColor mc = new MyColor();
        mc.A = a;
        mc.R = r;
        mc.G = g;
        mc.B = b;
        return mc;
    }

    public override bool Equals(object obj) {
        if (!(obj is MyColor))
            return false;
        MyColor color = (MyColor)obj;
        if(color.A == this.A && color.R == this.R && color.G == this.G && color.B == this.B)
            return true;
        return false;
    }
}

这篇关于在C#中查找大图中的Subimage的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆