C - 如何将 [600][400] 数组复制到 [4][4] 数组,然后随机化元素位置?

标签 c arrays multidimensional-array chunks

我正在尝试制作一个随机播放图像的函数,如下所示:shuffle

它的参数采用三个 600x400 RGB 数组来创建像素颜色。几个小时以来,我一直在努力集思广益,但我对实现它的方法感到很困惑。这是我尝试过的一个想法,但我不知所措并被难住了:

将每个 RGB 数组(R[][]、G[][] 和 B[][] 分别复制到它们各自的临时数组中。将临时数组拆分为 4x4。每个元素都将包含自己的二维数组和一 block 原始图像。然后使用随机库,我可以将元素分配到 4x4 中的新位置。如果不制作 42 个阵列(4x4 中每种颜色 16 个阵列,但 R、G 和 B 有 42 个阵列),我不知道如何做到这一点。我将不胜感激任何建议,或者这是我目前拥有的代码,但我暂停(或可能放弃)了以下工作:

            void Shuffle(unsigned char R[WIDTH][HEIGHT], unsigned char G[WIDTH][HEIGHT], unsigned char B[WIDTH][HEIGHT]){

            // Initialize 150x100 inner shuffle arrays. These arrays are chunks of the original image
            int shuffArrR[150][100] = {0};
            int shuffArrG[150][100] = {0};
            int shuffArrB[150][100] = {0};

            int row = 0, col = 0;

        /*
                                BOUNDARY INFO FOR 4x4 ARRAY:

                                 C1: C2: C3: C4:    hBound# (row):
                                -------------------->   1
                           R1:  |   |   |   |   |
                                -------------------->   2
                           R2:  |   |   |   |   |
                                -------------------->   3                       
                           R3:  |   |   |   |   |
                                -------------------->   4
                           R4:  |   |   |   |   |
                                -------------------->   5
                                |   |   |   |   |
                                v   v   v   v   v

                vBound# (col):  1   2   3   4   5

                            vBound:         hBound:         
                            #:  col:        #:  row:
                            1    0          1    0
                            2   150         2   100
                            3   300         3   200
                            4   450         4   300
                            5   600         5   400
        */
            // Define boundaries
            int const vBound1 = 0, vBound2 = 150, vBound3 = 300, vBound4 = 450;
            int const hBound1 = 0, hBound2 = 100, hBound3 = 200, hBound4 = 300;

            for(row; row < HEIGHT; row++){
                for(col; col < WIDTH; col++){

                    // Copy RGB arrays to shuffle arrays
                    shuffArrR[col][row] = R[col][row];
                    shuffArrG[col][row] = G[col][row];
                    shuffArrB[col][row] = B[col][row];

                    // Define 16 blocks in 4x4 array ------------------

                    // If in R1
                    if(row >= hBound1 && row <= hBound2){

                        // And in C1
                        if(col >= vBound1 && col <= vBound2){
                            // ** I stopped here after I realized how many arrays I'd have to make to account for every element in the 4x4 **
                        }

                    }
                }
            }

        }

最佳答案

使用更好的数据结构

现在,您正在使用多维数组,它有一定的优点和缺点,略微提到 elsewhere on SO .因为您正在做的是图像处理,所以性能对您来说可能至关重要,并且由于各种原因取消引用多维数组并不是最佳选择(即您可能会因非顺序读取而失去性能)。

有几种方法可以提高性能,同时让您的生活更轻松:

交错一维数组

意思是,你应该使用单个 unsigned char img[WIDTH * HEIGHT * COLORS]大批。这样做的好处是让您的代码也更易于维护,因为您可以通过更改常量 COLORS 来处理 RGB、B&W 和 RGBA 图像。 .要访问单个像素的给定颜色,您可以使用 img[y * width * COLORS + x * COLORS + color] .你也可以写一个宏来帮助解决这个问题,例如

#define INDEX_XYZ(x,y,color) ((y) * WIDTH * COLORS + (x) * COLORS + (color))

为了进一步提高函数的可用性,考虑将每个维度的大小以及颜色数量传递给它。例如,您可以将签名更改为...

void Shuffle(unsigned char image[], int height, int width, int colors);

这将允许您对任何大小(只要两个维度都可以被四整除)和任何颜色的图像使用相同的函数。您可能还想传递一个指示 segmentation 数的参数,这样您就可以根据需要进行 3×3 分割或 8×8 分割,而无需更改函数或重复代码。

将图像分割成片段

执行此操作的一种方法是为段创建数组...

unsigned char segments[SEG_HORI * SEG_VERT][WIDTH / SEG_HORI * HEIGHT / SEG_VERT * COLOR];

注意多维性 - 在这里很好,因为我们希望有许多单独的段来存储数据。

然后我们从原始数据复制数据:

// Calculate the height/width for the segments; you could do this as a macro too.
int seg_height = HEIGHT / SEG_VERT;
int seg_width = WIDTH / SEG_HORI;
// Iterate through the rows in the picture
for (int y = 0; y < HEIGHT; y++) 
{
    // Obtain the Y-coordinate of the segment.
    int segy = y / seg_height;

    // Iterate through the columns in the picture
    for (int x = 0; x < WIDTH; x++)
    {
        // Calculate the X-coordinate of the segment.
        int segx = x / seg_width,

        // Then calculate its index, using the X and Y coordinates.
            seg  = segy * SEG_HORI + segx,
        // Then, calculate the source index (from the image).
            src_idx = y * WIDTH * COLORS + x * COLORS,

        // Then, map the coordinates to the segment; notice that we take
        // modulos on the coordinates to get them to correctly map.
            dst_idx = y % seg_height * seg_width * COLORS + x % seg_width * COLORS;

        // Then copy the colors. You could also use memcpy(),
        // but the below should be more educational.
        for (int c = 0; c < COLORS; c++)
            segments[seg][dst_idx + c] = img[src_idx + c];
    }
}

现在,图像已被复制到片段中,您可以根据需要对它们重新排序,因为“片段”只是指针。例如,下面将交换左上角和右下角的部分。

unsigned char seg_temp[] = segments[0];
segments[0] = segments[15];
segments[15] = seg_temp;

最后,要完成流程并将各个段重新合并在一起,您需要反向重做上述流程;这应该很简单,所以我会把它留给你作为练习。

最后的笔记

如果您还没有,您应该熟悉 malloc() free() 功能,以及 memset() memcpy() .它们在未来应该会非常有用,并且还会提高此处的性能,因为您可以将所有内容复制到 n 中的目标数组(连同随机播放)。操作,而不是修改 2n 中的原始内容.

免责声明 1:我没有通过编译器运行任何代码。不保证它开箱即用。

免责声明 2:我也不声称代码经过了很好的优化。得给你留点事做。

关于C - 如何将 [600][400] 数组复制到 [4][4] 数组,然后随机化元素位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52999186/

相关文章:

ruby - 在 Ruby 中处理单个值或数组的最佳方法是什么

java - 使用带有 Swing 的鼠标绘制(单色)数组的最简单方法是什么?

C++ 并行数组

c - rand() 函数以概率选择可变数量的 IP

c - 如何修复链接器警告 : "function undefined" in kernel space?

C - 返回数组不起作用

ruby - 有没有办法使用两个 while 循环对 NDS 中子哈希的元素求和?

python - 如何使用索引向量对 3d ndarray 进行切片

c - MPI 将多个内部通信合并为一个内部通信

c - 如何使用指针打印字符数组中的每个字符?