Реализация функции SubImage на C

Это дополнительный вопрос для генератора двумерных гауссовских изображений в C, реализации двумерной бикубической интерполяции в C и метода подплоскости для общей двумерной плоскости данных в C #. Помимо генерации гауссовского изображения и бикубической интерполяции, я пытаюсь сделать в этом посте функцию субизображения версии C, чтобы ROI (область интереса) изображения могут быть извлечены.

Пример выходного фрагмента изображения:

SubImage

Экспериментальная реализация

  • SubMonoImage реализация функции: операция извлечения фрагментов изображения для MONOIMAGE состав.

    MONOIMAGE SubMonoImage(const MONOIMAGE image, unsigned int locationx, unsigned int locationy, unsigned int sizex, unsigned int sizey)
    {
        MONOIMAGE output = CreateMonoImage(sizex, sizey);
        for (size_t y = 0; y < sizey; y++)
        {
            for (size_t x = 0; x < sizex; x++)
            {
                if ((locationy + y) < image.XSIZE &&
                    (locationx + x) < image.YSIZE)          //  valid location
                {
                    output.IMAGE_DATA[GetMonoImageIndex(x, y, output)] = 
                        image.IMAGE_DATA[GetMonoImageIndex((locationx + x), (locationy + y), image)];
                }
            }
        }
        return output;
    }
    
  • SubRGBImage реализация функции: операция извлечения фрагментов изображения для RGBIMAGE состав.

    RGBIMAGE SubRGBImage(const RGBIMAGE image, unsigned int locationx, unsigned int locationy, unsigned int sizex, unsigned int sizey)
    {
        MONOIMAGE R = SubMonoImage(GetPlaneR(image), locationx, locationy, sizex, sizey);
        MONOIMAGE G = SubMonoImage(GetPlaneG(image), locationx, locationy, sizex, sizey);
        MONOIMAGE B = SubMonoImage(GetPlaneB(image), locationx, locationy, sizex, sizey);
        RGBIMAGE output = CreateRGBImageFromMonoImages(sizex, sizey, R, G, B);
        DeleteMonoImage(R);
        DeleteMonoImage(G);
        DeleteMonoImage(B);
        return output;
    }
    
  • basic_functions.h: Содержит несколько объявлений основных функций.

    /* Develop by Jimmy Hu */
    
    #ifndef BASIC_FUNCTIONS_H
    #define BASIC_FUNCTIONS_H
    
    #include "base.h"
    #include "imageio.h"
    
    MONOIMAGE CreateMonoImage(const unsigned int, const unsigned int);
    
    void DeleteMonoImage(MONOIMAGE);
    
    MONOIMAGE GetPlaneR(const RGBIMAGE);
    
    MONOIMAGE GetPlaneG(const RGBIMAGE);
    
    MONOIMAGE GetPlaneB(const RGBIMAGE);
    
    RGBIMAGE CreateRGBImage(const unsigned int, const unsigned int);
    
    RGBIMAGE CreateRGBImageFromMonoImages(const unsigned int, const unsigned int, MONOIMAGE, MONOIMAGE, MONOIMAGE);
    
    void DeleteRGBImage(RGBIMAGE);
    
    size_t GetMonoImageIndex(const size_t, const size_t, const MONOIMAGE);
    
    size_t GetRGBImageIndex(const size_t, const size_t, const RGBIMAGE);
    
    size_t clip(const size_t, const size_t, const size_t);
    
    float clip_float(const float, const float, const float);
    
    #endif
    
  • basic_functions.c: Содержит несколько основных определений функций.

    /* Develop by Jimmy Hu */
    
    #include "basic_functions.h"
    
    MONOIMAGE CreateMonoImage(const unsigned int sizex, const unsigned int sizey)
    {
        MONOIMAGE output;
        output.XSIZE = sizex;
        output.YSIZE = sizey;
        output.IMAGE_DATA = malloc(sizeof *output.IMAGE_DATA * sizex * sizey);
        if(output.IMAGE_DATA == NULL)
        {    
            printf(stderr, "Memory allocation error!");
            return output;
        }
        return output;
    }
    
    void DeleteMonoImage(MONOIMAGE image)
    {
        free(image.IMAGE_DATA);
        return;
    }
    
    MONOIMAGE GetPlaneR(const RGBIMAGE image)
    {
        MONOIMAGE output = CreateMonoImage(image.XSIZE, image.YSIZE);
        for (size_t y = 0; y < image.YSIZE; y++)
        {
            for (size_t x = 0; x < image.XSIZE; x++)
            {
                output.IMAGE_DATA[GetMonoImageIndex(x, y, output)] = 
                    image.IMAGE_DATA[GetRGBImageIndex(x, y, image)].channels[0];
            }
        }
        return output;
    }
    
    MONOIMAGE GetPlaneG(const RGBIMAGE image)
    {
        MONOIMAGE output = CreateMonoImage(image.XSIZE, image.YSIZE);
        for (size_t y = 0; y < image.YSIZE; y++)
        {
            for (size_t x = 0; x < image.XSIZE; x++)
            {
                output.IMAGE_DATA[GetMonoImageIndex(x, y, output)] = 
                    image.IMAGE_DATA[GetRGBImageIndex(x, y, image)].channels[1];
            }
        }
        return output;
    }
    
    MONOIMAGE GetPlaneB(const RGBIMAGE image)
    {
        MONOIMAGE output = CreateMonoImage(image.XSIZE, image.YSIZE);
        for (size_t y = 0; y < image.YSIZE; y++)
        {
            for (size_t x = 0; x < image.XSIZE; x++)
            {
                output.IMAGE_DATA[GetMonoImageIndex(x, y, output)] = 
                    image.IMAGE_DATA[GetRGBImageIndex(x, y, image)].channels[2];
            }
        }
        return output;
    }
    
    RGBIMAGE CreateRGBImage(const unsigned int sizex, const unsigned int sizey)
    {
        RGBIMAGE output;
        output.XSIZE = sizex;
        output.YSIZE = sizey;
        output.IMAGE_DATA = malloc(sizeof *output.IMAGE_DATA * sizex * sizey);
        if(output.IMAGE_DATA == NULL)
        {    
            printf(stderr, "Memory allocation error!");
            return output;
        }
        return output;
    }
    
    RGBIMAGE CreateRGBImageFromMonoImages(const unsigned int sizex, const unsigned int sizey, MONOIMAGE R, MONOIMAGE G, MONOIMAGE B)
    {
        RGBIMAGE output;
        output.XSIZE = sizex;
        output.YSIZE = sizey;
        output.IMAGE_DATA = malloc(sizeof *output.IMAGE_DATA * sizex * sizey);
        if (output.IMAGE_DATA == NULL)
        {    
            printf(stderr, "Memory allocation error!");
            return output;
        }
        if ((R.XSIZE != G.XSIZE) ||
            (G.XSIZE != B.XSIZE) ||
            (R.XSIZE != B.XSIZE) ||
            (R.YSIZE != G.YSIZE) ||
            (G.YSIZE != B.YSIZE) ||
            (R.YSIZE != B.YSIZE))
        {
            printf(stderr, "Input size inequal!");
            return output;
        }
        for (size_t y = 0; y < R.YSIZE; y++)
        {
            for (size_t x = 0; x < R.XSIZE; x++)
            {
                output.IMAGE_DATA[GetRGBImageIndex(x, y, output)].channels[0] = R.IMAGE_DATA[GetMonoImageIndex(x, y, R)];
                output.IMAGE_DATA[GetRGBImageIndex(x, y, output)].channels[1] = G.IMAGE_DATA[GetMonoImageIndex(x, y, G)];
                output.IMAGE_DATA[GetRGBImageIndex(x, y, output)].channels[2] = B.IMAGE_DATA[GetMonoImageIndex(x, y, B)];
            }
        }
        return output;
    }
    
    void DeleteRGBImage(RGBIMAGE image)
    {
        free(image.IMAGE_DATA);
        return;
    }
    
    size_t GetMonoImageIndex(const size_t x, const size_t y, const MONOIMAGE image)
    {
        return y * image.XSIZE + x;
    }
    
    size_t GetRGBImageIndex(const size_t x, const size_t y, const RGBIMAGE image)
    {
        return y * image.XSIZE + x;
    }
    
    size_t clip(const size_t input, const size_t lowerbound, const size_t upperbound)
    {
        if (input < lowerbound)
        {
            return lowerbound;
        }
        if (input > upperbound)
        {
            return upperbound;
        }
        return input;
    }
    
    float clip_float(const float input, const float lowerbound, const float upperbound)
    {
        if (input < lowerbound)
        {
            return lowerbound;
        }
        if (input > upperbound)
        {
            return upperbound;
        }
        return input;
    }
    
  • base.h: Содержит реализацию базового типа

    /* Develop by Jimmy Hu */
    
    #ifndef BASE_H
    #define BASE_H
    
    #include <math.h>
    #include <stdbool.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    #define MAX_PATH 256
    #define FILE_ROOT_PATH "./"
    
    #define True true
    #define False false
    
    typedef struct RGB
    {
        unsigned char channels[3];
    } RGB;
    
    typedef struct HSV
    {
        long double channels[3];    //  Range: 0 <= H < 360, 0 <= S <= 1, 0 <= V <= 255
    }HSV;
    
    typedef struct BMPIMAGE
    {
        char FILENAME[MAX_PATH];
    
        unsigned int XSIZE;
        unsigned int YSIZE;
        unsigned char FILLINGBYTE;
        unsigned char *IMAGE_DATA;
    } BMPIMAGE;
    
    typedef struct RGBIMAGE
    {
        unsigned int XSIZE;
        unsigned int YSIZE;
        RGB *IMAGE_DATA;
    } RGBIMAGE;
    
    typedef struct HSVIMAGE
    {
        unsigned int XSIZE;
        unsigned int YSIZE;
        HSV *IMAGE_DATA;
    } HSVIMAGE;
    
    typedef struct MONOIMAGE
    {
        unsigned int XSIZE;
        unsigned int YSIZE;
        unsigned char *IMAGE_DATA;
    } MONOIMAGE;
    
    typedef struct DOUBLEIMAGE
    {
        unsigned int XSIZE;
        unsigned int YSIZE;
        double *IMAGE_DATA;
    };
    
    #endif
    

Полный код тестирования

/* Develop by Jimmy Hu */

#include "base.h"
#include "basic_functions.h"
#include "imageio.h"

MONOIMAGE BicubicInterpolationMonoImage(MONOIMAGE image, const int, const int);

RGBIMAGE BicubicInterpolationRGBImage(RGBIMAGE image, const int, const int);

unsigned char BicubicPolate(const unsigned char*, const float, const float);

float CubicPolate(const float, const float, const float, const float, const float);

/*  Subimage extracting operation for MONOIMAGE structure
*/
MONOIMAGE SubMonoImage(const MONOIMAGE, unsigned int, unsigned int, unsigned int, unsigned int);

/*  Subimage extracting operation for RGBIMAGE structure
*/
RGBIMAGE SubRGBImage(const RGBIMAGE, unsigned int, unsigned int, unsigned int, unsigned int);

int main(int argc, char** argv)
{
    char *FilenameString;
    FilenameString = malloc( sizeof *FilenameString * MAX_PATH);
    
    printf("BMP image input file name:(ex:test): ");
    scanf("%s", FilenameString);
    BMPIMAGE BMPImage1 = bmp_file_read(FilenameString, false);
    RGBIMAGE RGBImage1;
    RGBImage1.XSIZE = BMPImage1.XSIZE;
    RGBImage1.YSIZE = BMPImage1.YSIZE;
    RGBImage1.IMAGE_DATA = raw_image_to_array(BMPImage1.XSIZE, BMPImage1.YSIZE, BMPImage1.IMAGE_DATA);

    RGBIMAGE RGBImage2 = SubRGBImage(RGBImage1, 150, 100, 250, 300);
    RGBIMAGE RGBImage3 = BicubicInterpolationRGBImage(RGBImage2, RGBImage2.XSIZE * 2, RGBImage2.YSIZE * 2);
    
    printf("file name for saving:(ex:test): ");
    scanf("%s", FilenameString);
    bmp_write(FilenameString, RGBImage3.XSIZE, RGBImage3.YSIZE, array_to_raw_image(RGBImage3.XSIZE, RGBImage3.YSIZE, RGBImage3.IMAGE_DATA));

    free(FilenameString);
    DeleteRGBImage(RGBImage1);
    DeleteRGBImage(RGBImage2);
    DeleteRGBImage(RGBImage3);
    return 0;
}

MONOIMAGE BicubicInterpolationMonoImage(MONOIMAGE image, const int newSizeX, const int newSizeY)
{
    MONOIMAGE output = CreateMonoImage(newSizeX, newSizeY);
    int originSizeX = image.XSIZE;
    int originSizeY = image.YSIZE;
    if (output.IMAGE_DATA == NULL)
    {
        printf(stderr, "Memory allocation error!");
        return output;
    }
    
    float ratiox = (float)originSizeX / (float)newSizeX;
    float ratioy = (float)originSizeY / (float)newSizeY;
    
    for (size_t y = 0; y < newSizeY; y++)
    {
        for (size_t x = 0; x < newSizeX; x++)
        {
            float xMappingToOrigin = (float)x * ratiox;
            float yMappingToOrigin = (float)y * ratioy;
            float xMappingToOriginFloor = floor(xMappingToOrigin);
            float yMappingToOriginFloor = floor(yMappingToOrigin);
            float xMappingToOriginFrac = xMappingToOrigin - xMappingToOriginFloor;
            float yMappingToOriginFrac = yMappingToOrigin - yMappingToOriginFloor;
            
            unsigned char ndata[4 * 4];
            for (int ndatay = -1; ndatay <= 2; ndatay++)
            {
                for (int ndatax = -1; ndatax <= 2; ndatax++)
                {
                    ndata[(ndatay + 1) * 4 + (ndatax + 1)] = image.IMAGE_DATA[
                        clip(yMappingToOriginFloor + ndatay, 0, originSizeY - 1) * originSizeX + 
                        clip(xMappingToOriginFloor + ndatax, 0, originSizeX - 1)
                        ];
                }
            }

            output.IMAGE_DATA[ y * newSizeX + x ] = BicubicPolate(ndata, xMappingToOriginFrac, yMappingToOriginFrac);
        }
    }
    return output;
}

RGBIMAGE BicubicInterpolationRGBImage(RGBIMAGE image, const int newSizeX, const int newSizeY)
{
    MONOIMAGE R = BicubicInterpolationMonoImage(GetPlaneR(image), newSizeX, newSizeY);
    MONOIMAGE G = BicubicInterpolationMonoImage(GetPlaneG(image), newSizeX, newSizeY);
    MONOIMAGE B = BicubicInterpolationMonoImage(GetPlaneB(image), newSizeX, newSizeY);
    RGBIMAGE output = CreateRGBImageFromMonoImages(newSizeX, newSizeY, R, G, B);
    DeleteMonoImage(R);
    DeleteMonoImage(G);
    DeleteMonoImage(B);
    return output;
}

unsigned char BicubicPolate(const unsigned char* const ndata, const float fracx, const float fracy)
{
    float x1 = CubicPolate( ndata[0], ndata[1], ndata[2], ndata[3], fracx );
    float x2 = CubicPolate( ndata[4], ndata[5], ndata[6], ndata[7], fracx );
    float x3 = CubicPolate( ndata[8], ndata[9], ndata[10], ndata[11], fracx );
    float x4 = CubicPolate( ndata[12], ndata[13], ndata[14], ndata[15], fracx );

    float output = clip_float(CubicPolate( x1, x2, x3, x4, fracy ), 0.0, 255.0);
    return (unsigned char)output;
}

float CubicPolate(const float v0, const float v1, const float v2, const float v3, const float fracy)
{
    float A = (v3-v2)-(v0-v1);
    float B = (v0-v1)-A;
    float C = v2-v0;
    float D = v1;
    return D + fracy * (C + fracy * (B + fracy * A));
}

MONOIMAGE SubMonoImage(const MONOIMAGE image, unsigned int locationx, unsigned int locationy, unsigned int sizex, unsigned int sizey)
{
    MONOIMAGE output = CreateMonoImage(sizex, sizey);
    for (size_t y = 0; y < sizey; y++)
    {
        for (size_t x = 0; x < sizex; x++)
        {
            if ((locationy + y) < image.XSIZE &&
                (locationx + x) < image.YSIZE)          //  valid location
            {
                output.IMAGE_DATA[GetMonoImageIndex(x, y, output)] = 
                    image.IMAGE_DATA[GetMonoImageIndex((locationx + x), (locationy + y), image)];
            }
        }
    }
    return output;
}

RGBIMAGE SubRGBImage(const RGBIMAGE image, unsigned int locationx, unsigned int locationy, unsigned int sizex, unsigned int sizey)
{
    MONOIMAGE R = SubMonoImage(GetPlaneR(image), locationx, locationy, sizex, sizey);
    MONOIMAGE G = SubMonoImage(GetPlaneG(image), locationx, locationy, sizex, sizey);
    MONOIMAGE B = SubMonoImage(GetPlaneB(image), locationx, locationy, sizex, sizey);
    RGBIMAGE output = CreateRGBImageFromMonoImages(sizex, sizey, R, G, B);
    DeleteMonoImage(R);
    DeleteMonoImage(G);
    DeleteMonoImage(B);
    return output;
}

Все предложения приветствуются.

Сводная информация:

  • На какой вопрос это продолжение?

    Генератор двумерных гауссовских изображений в C,

    Реализация двумерной бикубической интерполяции на языках C и

    Метод подплоскости для общей двумерной плоскости данных в C #.

  • Какие изменения были внесены в код с момента последнего вопроса?

    Я пытаюсь сделать в этом посте функцию подобраза версии C.

  • Почему запрашивается новый обзор?

    Если есть какие-то улучшения, пожалуйста, дайте мне знать.

Справка

1 ответ
1

Есть изображения, которые гораздо лучше подходят для просмотра прямоугольных обрезков:

struct Image {
    void *pixels;
    enum format pixel_format;
    size_t width;
    size_t height;
    size_t stride;
}

С участием pixels указывая на верхнюю левую позицию в исходном изображении, и stride скопировано с шага источника, то нам не нужно копировать данные. Если мы действительно хотим скопировать, это может быть отдельная функция. Это помогает разделить наши опасения.

Несвязанные, пожалуйста, не используйте имена ALL_CAPS для идентификаторов C. Обычно для макросов препроцессора используются заглавные буквы; их нужно различать, потому что они представляют собой текстовые замены, а не имена, и не ограничиваются определенной областью. Когда обычные имена пишутся заглавными буквами, становится сложнее выбрать макросы и проявить к ним необходимую осторожность.

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *