mirror of
https://gitee.com/Lyon1998/pikapython.git
synced 2025-01-15 17:02:53 +08:00
416 lines
13 KiB
C
416 lines
13 KiB
C
#include "PikaCV_Image.h"
|
|
#include "PikaCV_common.h"
|
|
#include "PikaStdData_List.h"
|
|
#include "dataStrs.h"
|
|
|
|
void PikaCV_Image___init__(PikaObj* self) {
|
|
if (NULL != obj_getStruct(self, "image")) {
|
|
/* already initialized */
|
|
return;
|
|
}
|
|
/* init */
|
|
PikaCV_Image image = {
|
|
.format = PikaCV_ImageFormat_Type_Unknown,
|
|
.width = 0,
|
|
.height = 0,
|
|
.size = 0,
|
|
};
|
|
obj_setStruct(self, "image", image);
|
|
_image_setData(self, NULL, 0);
|
|
}
|
|
|
|
uint8_t* _image_getData(PikaObj* self) {
|
|
PikaCV_Image* image = obj_getStruct(self, "image");
|
|
if (NULL == image) {
|
|
return NULL;
|
|
}
|
|
return obj_getBytes(self, "_data");
|
|
}
|
|
|
|
int _image_getDataSize(PikaObj* self) {
|
|
PikaCV_Image* image = obj_getStruct(self, "image");
|
|
if (NULL == image) {
|
|
return 0;
|
|
}
|
|
return obj_getBytesSize(self, "_data");
|
|
}
|
|
|
|
PIKA_RES _image_setData(PikaObj* self, uint8_t* data, int size) {
|
|
PikaCV_Image* image = obj_getStruct(self, "image");
|
|
if (NULL == image) {
|
|
return PIKA_RES_ERR_ARG_NO_FOUND;
|
|
}
|
|
obj_setBytes(self, "_data", data, size);
|
|
image->size = size;
|
|
return PIKA_RES_OK;
|
|
}
|
|
|
|
Arg* PikaCV_Image_data(PikaObj* self) {
|
|
PikaCV_Image* image = obj_getStruct(self, "image");
|
|
if (NULL == image) {
|
|
return NULL;
|
|
}
|
|
return arg_copy(obj_getArg(self, "_data"));
|
|
}
|
|
|
|
int PikaCV_Image_format(PikaObj* self) {
|
|
PikaCV_Image* image = obj_getStruct(self, "image");
|
|
if (NULL == image) {
|
|
return PikaCV_ImageFormat_Type_Unknown;
|
|
}
|
|
return image->format;
|
|
}
|
|
|
|
int PikaCV_Image_hight(PikaObj* self) {
|
|
PikaCV_Image* image = obj_getStruct(self, "image");
|
|
if (NULL == image) {
|
|
return 0;
|
|
}
|
|
return image->height;
|
|
}
|
|
|
|
void PikaCV_Image_loadJpeg(PikaObj* self, Arg* bytes) {
|
|
obj_setArg(self, "_data", bytes);
|
|
}
|
|
|
|
void PikaCV_Image_loadRGB565(PikaObj* self,
|
|
uint8_t* bytes,
|
|
int height,
|
|
int width) {
|
|
PikaCV_Image* image = obj_getStruct(self, "image");
|
|
if (NULL == image) {
|
|
return;
|
|
}
|
|
image->format = PikaCV_ImageFormat_Type_RGB565;
|
|
image->height = height;
|
|
image->width = width;
|
|
image->size = height * width * 2;
|
|
_image_setData(self, bytes, image->size);
|
|
}
|
|
|
|
void PikaCV_Image_loadRGB888(PikaObj* self,
|
|
uint8_t* bytes,
|
|
int height,
|
|
int width) {
|
|
PikaCV_Image* image = obj_getStruct(self, "image");
|
|
if (NULL == image) {
|
|
return;
|
|
}
|
|
image->format = PikaCV_ImageFormat_Type_RGB888;
|
|
image->height = height;
|
|
image->width = width;
|
|
image->size = height * width * 3;
|
|
_image_setData(self, bytes, image->size);
|
|
}
|
|
|
|
void PikaCV_Image_loadGray(PikaObj* self,
|
|
uint8_t* bytes,
|
|
int height,
|
|
int width) {
|
|
PikaCV_Image* image = obj_getStruct(self, "image");
|
|
if (NULL == image) {
|
|
return;
|
|
}
|
|
image->format = PikaCV_ImageFormat_Type_GRAY;
|
|
image->height = height;
|
|
image->width = width;
|
|
image->size = height * width;
|
|
_image_setData(self, bytes, image->size);
|
|
}
|
|
|
|
void PikaCV_Image_read(PikaObj* self, char* path) {
|
|
PikaCV_Image* image = obj_getStruct(self, "image");
|
|
if (NULL == image) {
|
|
return;
|
|
}
|
|
Arg* data_arg = arg_loadFile(NULL, path);
|
|
if (NULL == data_arg) {
|
|
return;
|
|
}
|
|
Args buffs = {0};
|
|
char* suffix = strsGetLastToken(&buffs, path, '.');
|
|
if (suffix == NULL) {
|
|
return;
|
|
}
|
|
if (strEqu(suffix, "jpg")) {
|
|
image->format = PikaCV_ImageFormat_Type_JPEG;
|
|
PikaCV_Image_loadJpeg(self, data_arg);
|
|
} else {
|
|
obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED);
|
|
__platform_printf("PikaCV_Image_read: unsupported format: %s\n",
|
|
suffix);
|
|
}
|
|
arg_deinit(data_arg);
|
|
strsDeinit(&buffs);
|
|
}
|
|
|
|
void PikaCV_Image_setPixel(PikaObj* self,
|
|
int channel,
|
|
int value,
|
|
int x,
|
|
int y) {
|
|
PikaCV_Image* image = obj_getStruct(self, "image");
|
|
if (NULL == image) {
|
|
return;
|
|
}
|
|
uint8_t* data = _image_getData(self);
|
|
if (image->format == PikaCV_ImageFormat_Type_RGB565) {
|
|
data[(y * image->width + x) * 2 + channel] = value;
|
|
} else if (image->format == PikaCV_ImageFormat_Type_RGB888) {
|
|
data[(y * image->width + x) * 3 + channel] = value;
|
|
} else if (image->format == PikaCV_ImageFormat_Type_GRAY) {
|
|
data[y * image->width + x] = value;
|
|
} else {
|
|
obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED);
|
|
__platform_printf("PikaCV_Image_setPixel: unsupported format: %d\n",
|
|
image->format);
|
|
}
|
|
}
|
|
|
|
int PikaCV_Image_getPixel(PikaObj* self, int channel, int x, int y) {
|
|
PikaCV_Image* image = obj_getStruct(self, "image");
|
|
if (NULL == image) {
|
|
return 0;
|
|
}
|
|
uint8_t* data = _image_getData(self);
|
|
if (image->format == PikaCV_ImageFormat_Type_RGB565) {
|
|
return data[(y * image->width + x) * 2 + channel];
|
|
} else if (image->format == PikaCV_ImageFormat_Type_RGB888) {
|
|
return data[(y * image->width + x) * 3 + channel];
|
|
} else if (image->format == PikaCV_ImageFormat_Type_GRAY) {
|
|
return data[y * image->width + x];
|
|
} else {
|
|
obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED);
|
|
__platform_printf("PikaCV_Image_getPixel: unsupported format: %d\n",
|
|
image->format);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int PikaCV_Image_size(PikaObj* self) {
|
|
PikaCV_Image* image = obj_getStruct(self, "image");
|
|
if (NULL == image) {
|
|
return 0;
|
|
}
|
|
return image->size;
|
|
}
|
|
|
|
int PikaCV_Image_width(PikaObj* self) {
|
|
PikaCV_Image* image = obj_getStruct(self, "image");
|
|
if (NULL == image) {
|
|
return 0;
|
|
}
|
|
return image->width;
|
|
}
|
|
|
|
void PikaCV_Image_write(PikaObj* self, char* path) {
|
|
uint8_t* data = _image_getData(self);
|
|
int size = _image_getDataSize(self);
|
|
if (NULL == data || size <= 0) {
|
|
obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED);
|
|
__platform_printf("PikaCV_Image_write: data is NULL or size is 0\n");
|
|
return;
|
|
}
|
|
FILE* fp = __platform_fopen(path, "wb+");
|
|
if (NULL == fp) {
|
|
obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED);
|
|
__platform_printf("PikaCV_Image_write: failed to open file: %s\n",
|
|
path);
|
|
return;
|
|
}
|
|
__platform_fwrite(data, 1, size, fp);
|
|
__platform_fclose(fp);
|
|
}
|
|
|
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
|
|
|
void PikaCV_Image_add(PikaObj* self, PikaObj* image) {
|
|
PikaCV_Image* src = obj_getStruct(self, "image");
|
|
PikaCV_Image* img = obj_getStruct(image, "image");
|
|
if (NULL == src || NULL == img) {
|
|
pika_assert(0);
|
|
return;
|
|
}
|
|
if (img->format != src->format) {
|
|
obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED);
|
|
__platform_printf("unsupported image format\n");
|
|
return;
|
|
}
|
|
if (img->size != src->size) {
|
|
obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED);
|
|
__platform_printf("illegal image size\n");
|
|
return;
|
|
}
|
|
|
|
uint8_t* src_data = _image_getData(self);
|
|
uint8_t* img_data = _image_getData(image);
|
|
|
|
int i;
|
|
uint8_t result;
|
|
|
|
/* add two images */
|
|
for (i = 0; i < (src->size) / 3; i++) {
|
|
result = src_data[i * 3] + img_data[i * 3];
|
|
src_data[i * 3] =
|
|
((result < MAX(src_data[i * 3], img_data[i * 3])) ? 255 : result);
|
|
|
|
result = src_data[i * 3 + 1] + img_data[i * 3 + 1];
|
|
src_data[i * 3 + 1] =
|
|
((result < MAX(src_data[i * 3 + 1], img_data[i * 3 + 1])) ? 255
|
|
: result);
|
|
|
|
result = src_data[i * 3 + 2] + img_data[i * 3 + 2];
|
|
src_data[i * 3 + 2] =
|
|
((result < MAX(src_data[i * 3 + 2], img_data[i * 3 + 2])) ? 255
|
|
: result);
|
|
}
|
|
|
|
obj_setBytes(self, "_data", src_data, src->size);
|
|
}
|
|
|
|
void PikaCV_Image_minus(PikaObj* self, PikaObj* image) {
|
|
PikaCV_Image* src = obj_getStruct(self, "image");
|
|
PikaCV_Image* img = obj_getStruct(image, "image");
|
|
if (NULL == src || NULL == img) {
|
|
pika_assert(0);
|
|
return;
|
|
}
|
|
if (img->format != src->format) {
|
|
obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED);
|
|
__platform_printf("unsupported image format\n");
|
|
return;
|
|
}
|
|
if (img->size != src->size) {
|
|
obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED);
|
|
__platform_printf("illegal image size\n");
|
|
return;
|
|
}
|
|
|
|
uint8_t* src_data = _image_getData(self);
|
|
uint8_t* img_data = _image_getData(image);
|
|
|
|
int i;
|
|
uint8_t result;
|
|
|
|
/* minus two images */
|
|
for (i = 0; i < (src->size) / 3; i++) {
|
|
result = src_data[i * 3] - img_data[i * 3];
|
|
src_data[i * 3] =
|
|
((result < MIN(src_data[i * 3], img_data[i * 3])) ? 0 : result);
|
|
|
|
result = src_data[i * 3 + 1] - img_data[i * 3 + 1];
|
|
src_data[i * 3 + 1] =
|
|
((result > MIN(src_data[i * 3 + 1], img_data[i * 3 + 1])) ? 0
|
|
: result);
|
|
|
|
result = src_data[i * 3 + 2] - img_data[i * 3 + 2];
|
|
src_data[i * 3 + 2] =
|
|
((result < MIN(src_data[i * 3 + 2], img_data[i * 3 + 2])) ? 0
|
|
: result);
|
|
}
|
|
|
|
obj_setBytes(self, "_data", src_data, (src->size));
|
|
}
|
|
|
|
void PikaCV_Image_merge(PikaObj* self, PikaObj* B, PikaObj* G, PikaObj* R) {
|
|
PikaCV_Image* src = obj_getStruct(self, "image");
|
|
PikaCV_Image* Channel_B = obj_getStruct(B, "image");
|
|
PikaCV_Image* Channel_G = obj_getStruct(G, "image");
|
|
PikaCV_Image* Channel_R = obj_getStruct(R, "image");
|
|
|
|
if (NULL == src || NULL == Channel_B || NULL == Channel_G ||
|
|
NULL == Channel_R) {
|
|
pika_assert(0);
|
|
return;
|
|
}
|
|
if (PikaCV_ImageFormat_Type_RGB888 != src->format) {
|
|
obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED);
|
|
__platform_printf("unsupported image format\n");
|
|
return;
|
|
}
|
|
if (PikaCV_ImageFormat_Type_GRAY != Channel_B->format ||
|
|
PikaCV_ImageFormat_Type_GRAY != Channel_G->format ||
|
|
PikaCV_ImageFormat_Type_GRAY != Channel_R->format) {
|
|
obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED);
|
|
__platform_printf("unsupported image format\n");
|
|
return;
|
|
}
|
|
if (Channel_B->size != Channel_G->size ||
|
|
Channel_B->size != Channel_R->size) {
|
|
obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED);
|
|
__platform_printf("illegal image size\n");
|
|
return;
|
|
}
|
|
|
|
src->size = Channel_B->size * 3;
|
|
src->height = Channel_B->height;
|
|
src->width = Channel_B->width;
|
|
|
|
Arg* src_new_data_arg = arg_setBytes(NULL, "", NULL, src->size);
|
|
uint8_t* src_data_new = arg_getBytes(src_new_data_arg);
|
|
|
|
uint8_t* B_data = _image_getData(B);
|
|
uint8_t* G_data = _image_getData(G);
|
|
uint8_t* R_data = _image_getData(R);
|
|
|
|
for (int i = 0; i < Channel_B->size; i++) {
|
|
src_data_new[i * 3] = R_data[i];
|
|
src_data_new[i * 3 + 1] = G_data[i];
|
|
src_data_new[i * 3 + 2] = B_data[i];
|
|
}
|
|
|
|
obj_setBytes(self, "_data", src_data_new, (src->size));
|
|
arg_deinit(src_new_data_arg);
|
|
}
|
|
|
|
PikaObj* PikaCV_Image_split(PikaObj* self) {
|
|
PikaCV_Image* src = obj_getStruct(self, "image");
|
|
|
|
if (NULL == src) {
|
|
pika_assert(0);
|
|
return NULL;
|
|
}
|
|
if (PikaCV_ImageFormat_Type_RGB888 != src->format) {
|
|
obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED);
|
|
__platform_printf("unsupported image format\n");
|
|
return NULL;
|
|
}
|
|
|
|
uint8_t* src_data = _image_getData(self);
|
|
Arg* arg_data_B = arg_setBytes(NULL, "", NULL, (src->size) / 3);
|
|
Arg* arg_data_G = arg_setBytes(NULL, "", NULL, (src->size) / 3);
|
|
Arg* arg_data_R = arg_setBytes(NULL, "", NULL, (src->size) / 3);
|
|
|
|
uint8_t* data_B = arg_getBytes(arg_data_B);
|
|
uint8_t* data_G = arg_getBytes(arg_data_G);
|
|
uint8_t* data_R = arg_getBytes(arg_data_R);
|
|
|
|
uint8_t* RGB[3] = {data_R, data_G, data_B};
|
|
|
|
for (int i = 0; i < (src->size) / 3; i++) {
|
|
RGB[0][i] = src_data[i * 3];
|
|
RGB[1][i] = src_data[i * 3 + 1];
|
|
RGB[2][i] = src_data[i * 3 + 2];
|
|
}
|
|
|
|
PikaObj* list = newNormalObj(New_PikaStdData_List);
|
|
PikaStdData_List___init__(list);
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
PikaObj* img = newNormalObj(New_PikaCV_Image);
|
|
PikaCV_Image___init__(img);
|
|
PikaCV_Image_loadGray(img, RGB[i], src->width, src->height);
|
|
Arg* token_arg = arg_setPtr(NULL, "", ARG_TYPE_OBJECT, img);
|
|
/* 添加到 list 对象 */
|
|
PikaStdData_List_append(list, token_arg);
|
|
/* 销毁 arg */
|
|
arg_deinit(token_arg);
|
|
}
|
|
|
|
arg_deinit(arg_data_B);
|
|
arg_deinit(arg_data_G);
|
|
arg_deinit(arg_data_R);
|
|
|
|
return list;
|
|
} |