簡體   English   中英

C#從子矩陣創建矩陣

[英]c# Creating Matrix from sub matrixes

你好,高技能的程序員

我有一個測試圖像1600x1600。 我將此作為灰度int值導入到矩陣中。 然后我從該矩陣創建了4x4子矩陣,並在這些塊中進行了一些數學運算並創建了新的塊。 現在我需要根據新的4x4塊再次創建一個新的矩陣(1600x1600)。但是我無法創建循環。 我總共有(1600/4 * 1600/4 = 160000)個子矩陣。 (當然我的程序不是靜態的,輸入圖像可以是任何東西。這是用於測試圖像的)。 現在這是我的結構。

Bitmap bmp = new Bitmap("c:\\test.jpg");
pictureBox1.Image = Image.FromFile("c:\\test.jpg");
int width = bmp.Width; int height = bmp.Height;

  while (y < height) {
      while (x < width) {
      pxl = bmp.GetPixel(x, y);
      int_grayscale_map[x, y] = GetGrayScale(pxl); //getgrayscale is function that returns int value
      x++;}
   y++;}

   int totalblocknumber = (width/4) * (height / 4); //160 000 in this case

現在,我從該代碼創建並填充了子塊。 有人在這里幫助過我(認為我們把1600x1600的圖像弄亂了,變成了4x4的片段)

Bitmap image = new Bitmap(FILENAME);

        List<List<List<Int32>>> grayscale_map_block = newList<List<List<Int32>>>();
         for (int row = 0; row < height; row += 4)
        {
            for (int col = 0; col < width; col += 4)
            {
                block.Add(new List<List<Color>>()  {
                     new List<Color>() { image.GetPixel(col, row), image.GetPixel(col + 1, row), image.GetPixel(col + 2, row), image.GetPixel(col + 3, row)} ,
                     new List<Color>() { image.GetPixel(col, row + 1), image.GetPixel(col + 1, row + 1), image.GetPixel(col + 2, row + 1), image.GetPixel(col + 3, row + 1)} ,
                     new List<Color>() { image.GetPixel(col, row + 2), image.GetPixel(col + 1, row + 2), image.GetPixel(col + 2, row + 2), image.GetPixel(col + 3, row + 2)} ,
                     new List<Color>() { image.GetPixel(col, row + 3), image.GetPixel(col + 1, row + 3), image.GetPixel(col + 2, row + 3), image.GetPixel(col + 3, row + 3)} ,
                });

                grayscale_map_block.Add(new List<List<Int32>>()  {
                     new List<Int32>() { GetGrayScale(image.GetPixel(col, row)), GetGrayScale(image.GetPixel(col + 1, row)), GetGrayScale(image.GetPixel(col + 2, row)), GetGrayScale(image.GetPixel(col + 3, row))} ,
                     new List<Int32>() { GetGrayScale(image.GetPixel(col, row + 1)), GetGrayScale(image.GetPixel(col + 1, row + 1)), GetGrayScale(image.GetPixel(col + 2, row + 1)), GetGrayScale(image.GetPixel(col + 3, row + 1))} ,
                     new List<Int32>() { GetGrayScale(image.GetPixel(col, row + 2)), GetGrayScale(image.GetPixel(col + 1, row + 2)), GetGrayScale(image.GetPixel(col + 2, row + 2)), GetGrayScale(image.GetPixel(col + 3, row + 2))} ,
                     new List<Int32>() { GetGrayScale(image.GetPixel(col, row + 3)), GetGrayScale(image.GetPixel(col + 1, row + 3)), GetGrayScale(image.GetPixel(col + 2, row + 3)), GetGrayScale(image.GetPixel(col + 3, row + 3))} ,
                });

            }
        }          // Getgrayscale is a function that input color return int value

就是這樣 現在我有160000個4x4矩陣,標為“ grayscale_map_block”,我正在使用此代碼來獲取grayscale_map_block [n] [x] [y] /第n個塊的元素x,y。 其中n = 0-總塊數

從這些模塊中,我必須巧妙地創建一個將各個部分組合在一起的循環。 新的1600x1600矩陣。 感謝您的幫助。

您可以這樣映射[x,y]-> [n,x_,y_]:

n = (y / 4) * (width/4) + (x/4);
x_ = x % 4;
y_ = y % 4;

這個想法是要計算n是垂直使用子塊的索引(y / 4),然后將其乘以一行中子塊的數量(寬度/ 4),然后加上子索引-水平(x / 4)塊。

然后使用模數運算符(%)計算子塊內的行,列地址。

從[n,x_,y_]映射到[x,y]

x = (n % (width / 4)) * 4 + x_;
y = (n / (width / 4)) * 4 + y_;

此處的想法是從單個索引n恢復子塊的水平和垂直索引。 垂直索引是n除以一行中子塊的數量,即(寬度/ 4)。 像素的垂直地址是垂直索引乘以4加上子塊行。 在水平方向上,再次使用模數運算符恢復塊的水平索引。 n%(寬度/ 4)。 然后類似地,乘以4並加x_以獲得水平像素索引(列索引)。

注意:僅當寬度和高度是4的倍數時,我提供的數學才有效。如果寬度和高度不是被4均分,那么您必須做稍微不同的數學運算,但是您還需要處理't 4 x 4,所以我假設您暫時不想這樣做-但如果需要,我也可以為您提供幫助。

好。 這是使用GetPixel和SetPixel的代碼(性能差,但易於理解。在理想的情況下,您應該使用LockBits。但現在就讓它保持簡單。)

除了使用列表之外,我還使用了2D數組。 這要簡單得多。 “塊”只是2D陣列的2D陣列。 我想您可以將其視為一個圖像,其中每個像素都是一個完整的圖像,或者可以將其視為一個微小的正方形圖像的網格。

看起來您已經可以控制位圖的加載和保存,因此我將省略該部分。

/// <summary>
/// Example Image Processing class
/// Demonstrates treating images as 2D arrays.
/// </summary>
public class ImageProcessor {
    /// <summary>
    /// Creates a 2D array of Colors from a bitmap.
    /// </summary>
    /// <param name="bm">The input bitmap</param>
    /// <returns>The output Color array</returns>
    public static Color[,] BitmapToColorArray(Bitmap bm) {
        int width = bm.Width;
        int height = bm.Height;
        Color[,] colorArray = new Color[width, height];
        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                colorArray[x, y] = bm.GetPixel(x, y);
            }
        }
        return colorArray;
    }

    /// <summary>
    /// Creates a Bitmap from a 2D array of Colors.
    /// </summary>
    /// <param name="colorArray">The input Color 2D array</param>
    /// <returns>The output bitmap</returns>
    public static Bitmap ColorArrayToBitmap(Color[,] colorArray) {
        int width = colorArray.GetLength(0);
        int height = colorArray.GetLength(1);
        Bitmap bm = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                bm.SetPixel(x, y, colorArray[x, y]);
            }
        }
        return bm;
    }

    /// <summary>
    /// Converts a Color to a gray value 0-255.
    /// </summary>
    /// <param name="color">The input color</param>
    /// <returns>The output gray value.</returns>
    public static int ColorToGray(Color color) {
        int gray = (color.R * 30 + color.G * 59 + color.B * 11) / 100;
        return gray;
    }

    /// <summary>
    /// Converts a gray value to a Color
    /// </summary>
    /// <param name="gray">The input gray value</param>
    /// <returns>The output Color</returns>
    public static Color GrayToColor(int gray) {
        return Color.FromArgb(gray, gray, gray);
    }

    /// <summary>
    /// Creates a 2D gray array from a 2D Color array
    /// </summary>
    /// <param name="colorArray">The input 2D Color array</param>
    /// <returns>The output 2D gray array</returns>
    public static int[,] ColorArrayToGrayArray(Color[,] colorArray) {
        int width = colorArray.GetLength(0);
        int height = colorArray.GetLength(1);
        int[,] grayArray = new int[width, height];
        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                grayArray[x,y] = ColorToGray(colorArray[x, y]);
            }
        }
        return grayArray;
    }

    /// <summary>
    /// Creates a 2D Color Array from a 2D gray array
    /// </summary>
    /// <param name="grayArray">The input 2D gray array</param>
    /// <returns>The output 2D Color array</returns>
    public static Color[,] GrayArrayToColorArray(int[,] grayArray) {
        int width = grayArray.GetLength(0);
        int height = grayArray.GetLength(1);
        Color[,] colorArray = new Color[width, height];
        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                colorArray[x, y] = GrayToColor(grayArray[x, y]);
            }
        }
        return colorArray;
    }

    /// <summary>
    /// Generic function to extract a 2D rectangular sub-area of an array as a new 2D array.
    /// </summary>
    /// <typeparam name="T">The generic type</typeparam>
    /// <param name="src">The input 2D array</param>
    /// <param name="srcx">The column of the top-left corner of the sub-area to extract</param>
    /// <param name="srcy">The row of the top-left corner of the sub-area to extract</param>
    /// <param name="dstWidth">The width of the sub-area to extract</param>
    /// <param name="dstHeight">The height o fthe sub-area to extract</param>
    /// <returns>The output 2D array</returns>
    public static T[,] SubArray<T>(T[,] src, int srcx, int srcy, int dstWidth, int dstHeight) {
        int srcWidth = src.GetLength(0);
        int srcHeight = src.GetLength(1);
        if (srcx < 0) throw new ArgumentOutOfRangeException();
        if (srcy < 0) throw new ArgumentOutOfRangeException();
        if (srcx + dstWidth > srcWidth) throw new ArgumentOutOfRangeException();
        if (srcy + dstHeight > srcHeight) throw new ArgumentOutOfRangeException();
        T[,] dst = new T[dstWidth, dstHeight];
        for (int dsty = 0; dsty < dstHeight; ++dsty) {
            for (int dstx = 0; dstx < dstWidth; ++dstx) {
                dst[dstx, dsty] = src[srcx + dstx, srcy + dsty];
            }
        }
        return dst;
    }

    /// <summary>
    /// Generic function to convert a 2D array into blocks (2D array of 2D arrays)
    /// </summary>
    /// <typeparam name="T">The generic type</typeparam>
    /// <param name="src">The input 2D array</param>
    /// <param name="blockSize">The width and height of each square block</param>
    /// <returns>The output 2D array of 2D arrays</returns>
    public T[,][,] ArrayToBlockArray<T>(T[,] src, int blockSize) {
        int srcWidth = src.GetLength(0);
        int srcHeight = src.GetLength(1);
        if (srcWidth % blockSize != 0) throw new Exception(string.Format("Width must be divisible by {0}", blockSize));
        if (srcHeight % blockSize != 0) throw new Exception(string.Format("Height must be divisible by {0}", blockSize));
        int dstWidth = srcWidth / blockSize;
        int dstHeight = srcHeight / blockSize;
        T[,][,] dst = new T[dstWidth, dstHeight][,]; // The syntax for creating new array of arrays is weird.
        for (int dsty = 0; dsty < dstHeight; ++dsty) {
            for (int dstx = 0; dstx < dstWidth; ++dstx) {
                dst[dstx, dsty] = SubArray(src, dstx * blockSize, dsty * blockSize, blockSize, blockSize);
            }
        }
        return dst;
    }

    /// <summary>
    /// Generic function to convert a 2D array of blocks (2D array of 2D arrays) back into a single 2D array.
    /// </summary>
    /// <typeparam name="T">The generic type</typeparam>
    /// <param name="src">The input 2D array of 2D arrays</param>
    /// <returns>The output 2D array</returns>
    public T[,] BlockArrayToArray<T>(T[,][,] src) {
        // assume uniform size
        int blockWidth = src[0, 0].GetLength(0);
        int blockHeight = src[0, 0].GetLength(1);
        int srcWidth = src.GetLength(0);
        int srcHeight = src.GetLength(1);
        int dstWidth = srcWidth * blockWidth;
        int dstHeight = srcHeight * blockHeight;
        T[,] dst = new T[dstWidth, dstHeight];
        for (int srcy = 0; srcy < srcHeight; ++srcy) {
            for (int srcx = 0; srcx < srcWidth; ++srcx) {
                for (int blocky = 0; blocky < blockHeight; ++blocky ) {
                    for (int blockx = 0; blockx < blockWidth; ++blockx) {
                        T[,] block = src[srcx, srcy];
                        if (block.GetLength(0) != blockWidth) throw new Exception(string.Format("Blocks must all have width {0}", blockWidth));
                        if (block.GetLength(1) != blockHeight) throw new Exception(string.Format("Blocks must all have height {0}", blockHeight));
                        int dstx = srcx * blockWidth + blockx;
                        int dsty = srcy * blockHeight + blocky;
                        dst[dstx, dsty] = src[srcx, srcy][blockx, blocky];
                    }
                }
            }
        }
        return dst;
    }

    /// <summary>
    /// Example function that does end-to-end processing of a Bitmap.
    /// </summary>
    /// <param name="srcBitmap">The input bitmap</param>
    /// <returns>The output bitmap</returns>
    public Bitmap Process(Bitmap srcBitmap) {
        const int blockSize = 4;

        Color[,] srcColorArray = BitmapToColorArray(srcBitmap);
        int[,] srcGrayArray = ColorArrayToGrayArray(srcColorArray);
        int[,][,] srcBlockArray = ArrayToBlockArray(srcGrayArray, blockSize);

        // TODO: Presumably you're going to modify the source block array.
        int[,][,] dstBlockArray = srcBlockArray; // PLACEHOLDER: do nothing for now.

        // Reconstitute a new bitmap from the (presumably modified) destination block array.
        int[,] dstGrayArray = BlockArrayToArray(dstBlockArray);
        Color[,] dstColorArray = GrayArrayToColorArray(dstGrayArray);
        Bitmap dstBitmap = ColorArrayToBitmap(dstColorArray);
        return dstBitmap;
    }
}

這是使用不同索引機制訪問2D數組的示例。 這里n是塊號, xy是4x4塊內的0-3索引。 這只是將(n,x,y)重新映射為(xx,yy),它們是原始2D數組中數據的索引。

class BlockData
{
    public int[,] data;

    internal void reindex(int n, int x, int y, out int xx, out int yy)
    {
        const int blockSize = 4;
        int width = data.GetLength(0);
        int columns = width / blockSize;
        int row = n / columns;
        int col = n % columns;
        xx = col * blockSize + x;
        yy = row * blockSize + y;
    }

    public int this[int n, int x, int y]
    {
        get
        {
            int xx, yy;
            reindex(n, x, y, out xx, out yy);
            return data[xx, yy];
        }
        set
        {
            int xx, yy;
            reindex(n, x, y, out xx, out yy);
            data[xx, yy] = value;
        }
    }
    public int this[int xx, int yy]
    {
        get
        {
            return data[xx, yy];
        }
        set
        {
            data[xx, yy] = value;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        BlockData b = new BlockData() { data = new int[1600, 1600] };
        b[10, 5] = 999;
        // (10,5) is in the 402nd block of 4x4 at (2,1) within that block.
        Debug.Assert(b[402, 2, 1] == 999);

        b[888, 3, 2] = 777;
        // The 888th block is row 2, column 88.  Its top-left is at ((88*4),(2*4)).
        // (352 + 3, 8 + 2) = (355, 10)
        Debug.Assert(b[355, 10] == 777);
    }
}

使用相同的策略,您也可以將數據內部存儲為一維數組,並提供從[n] [x] [y]到線性[i]的不同索引映射。

為對象提供數組索引運算符實際上只是“可愛”。 這不是必需的。 這個想法只是做數學計算要訪問的源數據的索引。 但這有助於說明我的觀點。

(性能注意事項:您可以對此進行優化,以便在初始化data如果希望加快訪問時間並避免一直調用data.GetLength(0) ,則可以預先計算blockSizewidthcolumns 。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM