Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DIP] add bmp encode to write image #412

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions examples/DIPDialect/resize4D_nchw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,17 @@
//===----------------------------------------------------------------------===//
#include "buddy/DIP/imgcodecs/loadsave.h"
#include <buddy/Core/Container.h>
#include <buddy/DIP/ImgContainer.h>
#include <buddy/DIP/DIP.h>
#include <buddy/DIP/ImageContainer.h>
#include <buddy/DIP/ImgContainer.h>
#include <iostream>
#include <math.h>

using namespace std;

void testImplementation(int argc, char *argv[]) {
// Read as colar image.
dip::Image<float, 4> inputBatch(argv[1], dip::DIP_RGB, true);
dip::Image<float, 4> inputBatch(argv[1], dip::DIP_RGB);

// Note : Both values in output image dimensions and scaling ratios must be
// positive numbers.
Expand All @@ -42,12 +42,12 @@ void testImplementation(int argc, char *argv[]) {
{1, 3, 224, 224} /*{image_cols, image_rows}*/);

// Define Img with the output of Resize4D.
intptr_t outSizes[3] = {output.getSizes()[2], output.getSizes()[3],
output.getSizes()[1]};
intptr_t outSizes[4] = {output.getSizes()[0], output.getSizes()[1],
output.getSizes()[2], output.getSizes()[3]};

Img<float, 3> outputImageResize4D(output.getData(), outSizes);
dip::Image<float, 4> outputImageResize4D(output.getData(), outSizes);

// dip::imwrite(argv[2], outputImageResize4D);
dip::imageWrite(argv[2], outputImageResize4D);

return;
}
Expand Down
132 changes: 131 additions & 1 deletion frontend/Interfaces/buddy/DIP/ImgContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,28 @@ inline bool ifBigEndian() {
return (*ptr == 0);
}

inline int validToInt(size_t sz) {
int valueInt = (int)sz;
assert((size_t)valueInt == sz);
return valueInt;
}

struct PaletteBlock {
unsigned char b, g, r, a;
};

// file bmp image palette
void FillPalette(PaletteBlock *palette, int bpp, bool negative = false) {
int i, length = 1 << bpp;
int xor_mask = negative ? 255 : 0;

for (i = 0; i < length; i++) {
int val = (i * 255 / (length - 1)) ^ xor_mask;
palette[i].b = palette[i].g = palette[i].r = (unsigned char)val;
palette[i].a = 0;
}
}

template <typename T, size_t N> class Image : public MemRef<T, N> {
public:
// Constructor initializes the image by loading from a file.
Expand All @@ -51,6 +73,9 @@ template <typename T, size_t N> class Image : public MemRef<T, N> {
// norm: Indicates whether to normalize pixel values (default is false).
Image(std::string filename, ImageModes mode, bool norm = false);

// from data to initialize image
Image(T *data, intptr_t sizes[N]);

// Retrieves the name of the current image format as a string.
std::string getFormatName() const {
switch (this->imageFormat) {
Expand All @@ -68,6 +93,8 @@ template <typename T, size_t N> class Image : public MemRef<T, N> {
size_t getHeight() const { return this->height; }
// Returns the bit depth of the image.
int getBitDepth() const { return this->bitDepth; }
// Write a image
static void imageWrite(const std::string &filename, Image<T, N> &image);

private:
// Enum to represent supported image formats.
Expand All @@ -90,12 +117,19 @@ template <typename T, size_t N> class Image : public MemRef<T, N> {
void determineFormat(const std::vector<uint8_t> &fileData);
// Decodes a BMP image from raw file data.
bool decodeBMP(const std::vector<uint8_t> &fileData);
// Decodes a PNG image from raw file data.
// encode image format
int findFormat(const std::string &_ext);
// BMP image encode
void BMPEncode(const std::string &filename, Image<T, N> &image);
#ifdef BUDDY_ENABLE_PNG
// Decodes a PNG image from raw file data.
bool decodePNG(const std::vector<uint8_t> &fileData);
#endif
};

template <typename T, std::size_t N>
Image<T, N>::Image(T *data, intptr_t sizes[N]): MemRef<T, N>(data, sizes) {}

// Image Container Constructor
// Constructs an image container object from the image file path.
template <typename T, std::size_t N>
Expand Down Expand Up @@ -616,6 +650,102 @@ bool Image<T, N>::decodePNG(const std::vector<uint8_t> &fileData) {
}
#endif

template <typename T, size_t N>
int findFormat(const std::string &_ext){
if (_ext.size() <= 1)
return 0;

const char *ext = strrchr(_ext.c_str(), '.');
if (!ext)
return 0;

if (strcmp(ext, ".bmp") == 0) {
return 1;
} else {
std::cerr << "Unsupported to generate" << ext << "format image" << std::endl;
return 0;
}
}

template <typename T, size_t N>
static void imageWrite(const std::string &filename, Image<T, N> &image){
int imformat = findFormat<T, N>(filename);
switch (imformat) {
case 1:
BMPEncode(filename, image);
break;
default:
return;
}
return;
}

template <typename T, size_t N>
void BMPEncode(const std::string &filename, Image<T, N> &image){
std::ofstream bmp(filename, std::ios::binary);
if (!bmp) {
std::cerr << "Failed to create file" << std::endl;
return;
}
int width = image.getSizes()[3];
int height = image.getSizes()[2];
int channels = image.getSizes()[1];
// Align each row of data with 4 bytes
int fileStep = (width * channels + 3) & -4;
int bitmapHeaderSize = 40;
int paletteSize = channels > 1 ? 0 : 1024;
int headerSize = 14 /* fileheader */ + bitmapHeaderSize + paletteSize;
size_t fileSize = (size_t)fileStep * height + headerSize;
PaletteBlock palette[256];
// Fixed value in BMP
int zero = 0;
int one = 1;
char zeropad[] = "\0\0\0\0";

// Write file header
bmp.write("BM", 2);
int fileSizeInt = validToInt(fileSize);
bmp.write(reinterpret_cast<char*>(&fileSizeInt), 4);
bmp.write(reinterpret_cast<char*>(&zero), 4);
bmp.write(reinterpret_cast<char*>(&headerSize), 4);

// Write bitmap header
bmp.write(reinterpret_cast<char*>(&bitmapHeaderSize), 4);
bmp.write(reinterpret_cast<char*>(&width), 4);
bmp.write(reinterpret_cast<char*>(&height), 4);
bmp.write(reinterpret_cast<char*>(&one), 2);
int bitDepth = channels << 3;
bmp.write(reinterpret_cast<char*>(&(bitDepth)), 2);
bmp.write(reinterpret_cast<char*>(&zero), 4);
bmp.write(reinterpret_cast<char*>(&zero), 4);
bmp.write(reinterpret_cast<char*>(&zero), 4);
bmp.write(reinterpret_cast<char*>(&zero), 4);
bmp.write(reinterpret_cast<char*>(&zero), 4);
bmp.write(reinterpret_cast<char*>(&zero), 4);

// Write palette
if (channels == 1) {
FillPalette(palette, 8);
bmp.write(reinterpret_cast<char*>(&palette), sizeof(palette));
}

// Write image data
int step = width * height;
T *data = image.getData();
for (int y = height - 1; y >= 0; y--) {
for (int i = 0; i < width; i++) {
for (int t = channels - 1; t >= 0; t--) {
unsigned char pixel= static_cast<unsigned char>(data[y * width + i + t * step]);
bmp.write(reinterpret_cast<char*>(&pixel), 1);
}
}
if (fileStep > width * channels)
bmp.write(zeropad, fileStep - width * channels);
}

bmp.close();
}

} // namespace dip

#endif // FRONTEND_INTERFACES_BUDDY_DIP_IMGCONTAINER