diff --git a/Image.cpp b/Image.cpp new file mode 100644 index 0000000..37b899c --- /dev/null +++ b/Image.cpp @@ -0,0 +1,508 @@ +#include "Image.h" +using namespace std; + +Image::Image(int w, int h, int c, std::vector const& _data) +{ + if (c != 1 && c != 3) + throw std::exception("The channels must be 1 or 3"); + if (w < 1 || h < 1) + throw std::exception("the arguments are invalid"); + width = w; + height = h; + channels = c; + refCount = new int; + *refCount = 1; + ROI = width; + data = new uint8_t[width * 3 * height]; + if (!_data.empty()) + memcpy(data, _data.data(), width * 3 * height); + else + { + for (int i = 0; i < width * 3 * height; i++) + { + data[i] = 0; + } + } +} + +Image::Image(Image const& other, int tl_x, int tl_y, int ROI_width, int ROI_height) +{ + if (tl_x<0 || tl_y + ROI_width > other.ROI || tl_y<0 || tl_x + ROI_height>other.height) + throw std::invalid_argument("Bad view image dimension"); + width = ROI_width; + height = ROI_height; + ROI = other.ROI; + channels = other.channels; + data = other.data + tl_x * ROI + tl_y; + refCount = (other.refCount); + (*refCount)++; +} + +Image::Image(Image const& other) + :width(other.width), height(other.height), ROI(other.ROI), channels(other.channels) +{ + data = other.data; + refCount = (other.refCount); + (*refCount)++; +} + +Image::~Image() +{ + if (refCount) + { + if (*refCount == 1) + { + delete refCount; + delete[] data; + } + else + (*refCount)--; + } +} + + +std::vector Image::at(int i, int j)const { + if (i < 0 || i >= height || j < 0 || j >= width) { + throw std::out_of_range("Index out of range"); + } + + std::vector pixel(channels); + for (int c = 0; c < channels; ++c) { + pixel[c] = data[(i * width * channels) + (j * channels) + c]; + } + return pixel; +} + +uint8_t Image::at(int i, int j, int c) { + if (i < 0 || i >= height || j < 0 || j >= width || c < 0 || c>2) + throw out_of_range("Index out of range"); + return data[(i * width * channels) + (j * channels) + c]; +} + +uint8_t* Image::ptr(int i) +{ + if (i<0 || i>height) throw out_of_range("Index out of range"); + return data + i * width * channels; +} + +uint8_t* Image::ptr(int i, int j) +{ + if (i<0 || i>height || j<0 || j>width) throw out_of_range("Index out of range"); + return data + i * width * channels + j * channels; +} + +uint8_t* Image::ptr(int i, int j, int c) +{ + if (i<0 || i>height || j<0 || j>width || c < 0 || c>2) throw out_of_range("Index out of range"); + return data + i * width * channels + j * channels + c; +} + + +Image Image::row(int y) const +{ + if (y > height-1) + throw invalid_argument("index out of range"); + Image img(width, 1, channels); + for (int j = 0; j < width; j++) + { + img.setAllPixel(0, j, at(y,j)); + } + return img; +} + +Image Image::col(int x) const +{ + if (x > width-1) + throw invalid_argument("index out of range"); + Image img(1, height, channels); + for (int i = 0; i < height; i++) + { + img.setAllPixel(i, 0, at(i, x)); + } + return img; +} + + +tuple Image::getSize() +{ + return make_tuple(width, height); +} + +bool Image::empty() +{ + bool res= width * height == 0 || data == nullptr; + if (res) + return res; + res = true; + for (int i = 0; i < width * 3 * height; i++) + { + if (data[i] != 0) + return false; + } + return true; +} + +Image Image::clone()const +{ + vector res; + for (int i = 0; i < width * height * channels; i++) + { + res.push_back(data[i]); + } + Image m(width, height, channels, res); + return m; +} + +vector> Image::splitChannels()const +{ + vectorred; + vectorgreen; + vectorblue; + for (int index = 0; index < width * height * channels; index++) + { + if (index % 3 == 0) + red.push_back(data[index]); + else + { + if (index % 3 == 1) + green.push_back(data[index]); + else + blue.push_back(data[index]); + } + } + vector>res({ red,green,blue }); + return res; +} + +vector Image::margeChannels(vector>v) +{ + if (v.size() != 3) + throw exception("the input is invalid"); + if(v[0].size()!=v[1].size()|| v[0].size() != v[2].size()) + throw exception("the input is invalid"); + vectorres; + for (int i = 0; i < v[0].size();i++) + { + res.push_back(v[0][i]); + res.push_back(v[1][i]); + res.push_back(v[2][i]); + } + return res; +} + +vector Image::getData() +{ + vectordata; + for (int i = 0; i < width*channels * height; i++) + { + data.push_back(this->data[i]); + } + return data; +} + + +Image Image::operator+(Image const& other) const +{ + if (width != other.width && height != other.height) + throw invalid_argument("the argument is invalid"); + if (width == other.width) + { + int c = other.channels == 3 || channels == 3 ? 3 : 1; + Image res(width, height + other.height, c); + int index = 0; + for (int i = 0; i < width * height * channels; i++) + { + res.data[index++] = data[i]; + } + for (int i = 0; i < other.width * other.height * other.channels; i++) + { + res.data[index++] = other.data[i]; + } + return res; + } + else + { + int c = other.channels == 3 || channels == 3 ? 3 : 1; + Image res(width + other.width, height, c); + int index = 0; + int i1 = 0; + int i2 = 0; + for (int j = 0; j < height; j++) + { + for (int i = 0; i < width*3; i++) + { + res.data[index++] = data[i1++]; + } + for (int i = 0; i < other.width*3; i++) + { + res.data[index++] = other.data[i2++]; + } + } + return res; + } +} + +Image Image::operator+(uint8_t value) const +{ + Image m(width, height, channels); + for (int index = 0; index < width * height * channels; index++) + { + if (data[index] + value > 255) + { + throw invalid_argument("the argument is invalid!!"); + } + m.data[index] = data[index] + value; + } + return m; +} + +Image Image::operator-(uint8_t value) const +{ + Image m(width, height, channels); + for (int index = 0; index < width * height * channels; index++) + { + if (data[index] - value<0) + { + throw invalid_argument("the argument is invalid!!"); + } + m.data[index] = data[index] - value; + + } + return m; +} + +bool Image::operator==(Image const& other) const +{ + if (width != other.width || height != other.height || channels != other.channels) + throw exception("It is impossible to compare objects with different dimensions"); + for (int i = 0; i < width * height * channels; i++) + { + if (other.data[i] != data[i]) + return false; + } + return true; +} + +bool Image::operator==(uint8_t const& value) const +{ + for (int i = 0; i < width * height * channels; i++) + { + if (data[i] != value) + return false; + } + return true; +} + +Image Image::operator=(Image const& other) +{ + Image m; + m.width = other.width; + height = other.height; + ROI = other.ROI; + channels = other.channels; + data = other.data; + refCount = (other.refCount); + (*refCount)++; + return m; +} + + +Image Image::readImage(string filename) +{ + int width=0, height=0; + vector pixels; + + ifstream file(filename, ios::binary); + if (!file.is_open()) { + throw runtime_error("Unable to open file"); + } + + file.seekg(18, ios::beg); + file.read(reinterpret_cast(&width), sizeof(width)); + file.read(reinterpret_cast(&height), sizeof(height)); + + file.seekg(54, ios::beg); // Skip to pixel data + + int rowSize = ((width * 3 + 3) / 4) * 4; // Calculate padded row size + int padding = rowSize - width * 3; + pixels.resize(width * 3 * height); + for (int i = height-1; i >=0; i--) { + file.read(reinterpret_cast(&pixels[i* width*3]), width*3); + file.seekg(padding, ios::cur); + } + + file.close(); + + Image result(width, height, 3, pixels); + return result; +} + +void Image::displayImage(const Image& img,int delay) +{ + int rowSize = img.width * 3; // Calculate padded row size + int padding = (((img.width * 3 + 3) / 4) * 4) - img.width * 3; + int rowSizeWithPadding = ((img.width * 3 + 3) / 4) * 4; + vectordata; + uint8_t* data2 = new uint8_t[rowSizeWithPadding * img.height]; + int i = 0; + for (int y = 0; y (&fileSize), 4); // File size + bmpFile.write("\0\0\0\0", 4); // Reserved + int offsetToData = 54; + bmpFile.write(reinterpret_cast(&offsetToData), 4); // Offset to image data + + // DIB Header (BITMAPINFOHEADER) + int headerSize = 40; + bmpFile.write(reinterpret_cast(&headerSize), 4); // DIB header size + bmpFile.write(reinterpret_cast(&image.width), 4); // Image width + bmpFile.write(reinterpret_cast(&image.height), 4); // Image height + short planes = 1; + bmpFile.write(reinterpret_cast(&planes), 2); // Planes + short bitsPerPixel = 24; + bmpFile.write(reinterpret_cast(&bitsPerPixel), 2); // Bits per pixel + int compression = 0; + bmpFile.write(reinterpret_cast(&compression), 4); // Compression method + bmpFile.write(reinterpret_cast(&imageSize), 4); // Image size + int resolutionX = 2835; // Pixels per meter (72 DPI) + int resolutionY = 2835; // Pixels per meter (72 DPI) + bmpFile.write(reinterpret_cast(&resolutionX), 4); // Horizontal resolution + bmpFile.write(reinterpret_cast(&resolutionY), 4); // Vertical resolution + int colorsUsed = 0; + bmpFile.write(reinterpret_cast(&colorsUsed), 4); // Colors in color table + int importantColors = 0; + bmpFile.write(reinterpret_cast(&importantColors), 4); // Important color count + + // Write image data (bottom to top) + for (int y = image.height - 1; y >= 0; y--) { + for (int x = 0; x < image.width; x++) { + int index = (y * image.width + x)*3 ; + bmpFile.write(reinterpret_cast(&image.data[index]), 1); // Blue channel + bmpFile.write(reinterpret_cast(&image.data[index + 1]), 1); // Green channel + bmpFile.write(reinterpret_cast(&image.data[index + 2]), 1); // Red channel + } + // Write padding bytes + for (int p = 0; p < padding; p++) { + bmpFile.write("\0", 1); + } + } + + bmpFile.close(); +} + + +void Image::waitKey(int delay) +{ + this_thread::sleep_for(std::chrono::seconds(delay)); +} + +Image Image::resize(const Image& src, tuple const size) +{ + Image image = src; + int oldWidth = src.width; + int oldHeight = src.height; + int newWidth = get<0>(size); + int newHeight = get<1>(size); + Image resImage(newWidth, newHeight); + for (int y = 0; y < newHeight; ++y) { + for (int x = 0; x < resImage.width; ++x) { + float gx = ((float)(x + 0.5) / newWidth) * oldWidth - 0.5; + float gy = ((float)(y + 0.5) / newHeight) * oldHeight - 0.5; + int gxi = static_cast(gx); + int gyi = static_cast(gy); + float c00r = image.at(gyi, gxi, 0); + float c00g = image.at(gyi, gxi, 1); + float c00b = image.at(gyi, gxi, 2); + float c10r = (gxi + 1 < oldWidth) ? image.at(gyi, gxi + 1, 0) : c00r; + float c10g = (gxi + 1 < oldWidth) ? image.at(gyi, gxi + 1, 1) : c00g; + float c10b = (gxi + 1 < oldWidth) ? image.at(gyi, gxi + 1, 2) : c00b; + float c01r = (gyi + 1 < oldHeight) ? image.at(gyi + 1, gxi, 0) : c00r; + float c01g = (gyi + 1 < oldHeight) ? image.at(gyi + 1, gxi, 1) : c00g; + float c01b = (gyi + 1 < oldHeight) ? image.at(gyi + 1, gxi, 2) : c00b; + float c11r = (gxi + 1 < oldWidth && gyi + 1 < oldHeight) ? image.at(gyi + 1, gxi + 1, 0) : c00r; + float c11g = (gxi + 1 < oldWidth && gyi + 1 < oldHeight) ? image.at(gyi + 1, gxi + 1, 1) : c00g; + float c11b = (gxi + 1 < oldWidth && gyi + 1 < oldHeight) ? image.at(gyi + 1, gxi + 1, 2) : c00b; + float wx = gx - gxi; + float wy = gy - gyi; + uint8_t r = (1 - wx) * (1 - wy) * c00r + wx * (1 - wy) * c10r + (1 - wx) * wy * c01r + wx * wy * c11r; + uint8_t g = (1 - wx) * (1 - wy) * c00g + wx * (1 - wy) * c10g + (1 - wx) * wy * c01g + wx * wy * c11g; + uint8_t b = (1 - wx) * (1 - wy) * c00b + wx * (1 - wy) * c10b + (1 - wx) * wy * c01b + wx * wy * c11b; + vector pixel = { r, g, b }; + resImage.setAllPixel(y, x, pixel); + } + } + return resImage; +} + +int Image::total() +{ + return width * height*channels; +} + + +void Image::setAllPixel(int i, int j, const vector& pixel) +{ + + if (pixel.size() < 0 || pixel.size() > 3 || i < 0 || i >= height || j < 0 || j >= width) + throw std::invalid_argument("Index out of range"); + for (int c = 0; c < channels; c++) + { + setPixelCH(i, j, c, pixel.at(c)); + } +} + +void Image::setPixelCH(int i, int j, int c, int value) +{ + if (value < 0 || value>255) + throw invalid_argument("Index out of range"); + if (i<0 || i>height || j<0 || j>width || c < 0 || c>2) + throw invalid_argument("Index out of range"); + data[(i * width * channels) + (j * channels) + c] = value; +} diff --git a/Image.h b/Image.h new file mode 100644 index 0000000..6ad55b2 --- /dev/null +++ b/Image.h @@ -0,0 +1,132 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +class Image +{ +public: + int width; + int height; + int channels; + int ROI; + int* refCount; + uint8_t* data; + + //defult c'tor + Image() + { + refCount = new int; + data = nullptr; + } + + //c'tor + Image(int w, int h, int c = 3, std::vector const& _data = {}); + + //view c'tor + Image(Image const& other, int tl_x, int tl_y, int ROI_width, int ROI_height); + + //copy c'tor + Image(Image const& other); + + //move c'tor + Image(Image&& other)noexcept : + width(other.width), height(other.height), ROI(other.ROI), channels(other.channels) + { + data = other.data; + other.data = nullptr; + refCount = (other.refCount); + other.refCount = nullptr; + } + + //d'tor + ~Image(); + + + static Image readImage(std::string filename); + + static void displayImage(const Image& img,int delay); + + static void writeImage(const std::string& filename, const Image& image); + + + static void waitKey(int delay = 0); + + static Image resize(const Image& src, std::tuple const size); + + int total(); + + //return a tuple of the width and height + std::tuple getSize(); + + + //get a row, a col and a vector of three number- B,G,R- and set in this place this vector of pixel + void setAllPixel(int i, int j, const std::vector& pixel); + + //get a row, a col and number-0/1/2 and value - and set to specific channel in a pixel- 0-B, 1-G, 2-R the value + void setPixelCH(int i, int j, int c, int value); + + + //get a number of row and return a new Image of width*1 with the data of this row + Image row(int y) const; + + //get a number of col and return a new Image of 1*height with the data of this col + Image col(int x) const; + + //return true if the image is empty + bool empty(); + + //return new image by copy the data + Image clone()const; + + //split the data of the image to three vector of B,G,R + std::vector>splitChannels()const; + + //get three vectors - B,G,R and marge them together + static std::vectormargeChannels(std::vector>v); + + //return the data of the image + std::vectorgetData(); + + + //returns the location of the row and column and the color sent + uint8_t at(int i, int j, int c); + + //returns the location of the row and column sent + std::vector at(int i, int j)const; + + + //pointer to start of a raw + uint8_t* ptr(int i); + + //pointer to start of a pixel + uint8_t* ptr(int i, int j); + + //pointer to specific channel in a pixel + uint8_t* ptr(int i, int j, int c); + + + //like copy c'tor + Image operator=(Image const& other); + + //add to all the pixels the value + Image operator +(uint8_t value) const; // by element + + //connect tow Image if match + Image operator+(Image const& other) const; + + //sub to all the pixels the value + Image operator -(uint8_t value) const; // by element + + // compare by element to other image + bool operator ==(Image const& other) const; // compare by element to other image + + // compare all elements to value + bool operator ==(uint8_t const& value) const; // compare all elements to value + +}; + diff --git a/Image.natvis b/Image.natvis new file mode 100644 index 0000000..0150a3a --- /dev/null +++ b/Image.natvis @@ -0,0 +1,26 @@ + + + + + + + + + + + + + UINT8 + + + 3 + + width + height + data + width*3 + + + + \ No newline at end of file diff --git a/test1.cpp b/test1.cpp new file mode 100644 index 0000000..0e545ae --- /dev/null +++ b/test1.cpp @@ -0,0 +1,539 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#ifdef _DEBUG +// the debug version that corresponds to the opencv_world420d.dll: +#pragma comment(lib, "opencv_world4100d.lib") +#else +// the release version that corresponds to the opencv_world420.dll: +#pragma comment(lib, "opencv_world4100.lib") +#endif + +#include "doctest.h" +#include "Image.h" +#include +#include +#define _CRTDBG_MAP_ALLOC //to get more details +#include +#include //for malloc and free + +using namespace std; +using namespace cv; + +TEST_CASE("check the memory management") +{ + _CrtMemState sOld; + _CrtMemState sNew; + _CrtMemState sDiff; + + _CrtMemCheckpoint(&sOld);//save the memory state + + { + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + auto data = img.getData(); + Image img2(img.width, img.height, 3, data); + Image img3(3, 3, 3); + Image img4 = img; + Image img5(img); + } + + _CrtMemCheckpoint(&sNew);//save the new memory state + + //if (_CrtMemDifference(&sDiff, &sOld, &sNew)) // if there is a difference + //{ + // OutputDebugString(L"-----------_CrtMemDumpStatistics ---------"); + // _CrtMemDumpStatistics(&sDiff); + // OutputDebugString(L"-----------_CrtMemDumpAllObjectsSince ---------"); + // _CrtMemDumpAllObjectsSince(&sOld); + // OutputDebugString(L"-----------_CrtDumpMemoryLeaks ---------"); + // _CrtDumpMemoryLeaks(); + //} + + CHECK(!_CrtMemDifference(&sDiff, &sOld, &sNew));// if there is a difference +} + +TEST_CASE("check the readImage function with invalid argumant") +{ + CHECK_THROWS_AS(Image::readImage("rest8.BMP"), runtime_error); +} + +TEST_CASE("check the readImage function") +{ + Mat m = imread("C:\\Users\\The user\\Desktop\\rest8.BMP"); + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + CHECK(img.width == m.cols); + CHECK(img.height == m.rows); + bool same = true; + for (int i = 0; i < img.width * img.height * img.channels; i++) + { + if (img.data[i] != m.data[i]) + same = false; + } + CHECK(same==true); +} + +TEST_CASE("check the readImage function with invalid argumant") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + CHECK_THROWS_AS(Image::writeImage("C:\\Users\\The user\\Desktop\\aaaaaa\\rest8.BMP",img), runtime_error); +} + +TEST_CASE("check the writeImage function") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + Image::writeImage("tryWriteImage.bmp", img); + Image img2 = Image::readImage("tryWriteImage.bmp"); + + CHECK(img.width == img2.width); + CHECK(img.height == img2.height); + bool same = true; + for (int i = 0; i < img.width * img.height * img.channels; i++) + { + if (img.data[i] != img2.data[i]) + same = false; + } + CHECK(same == true); +} + +//TEST_CASE("check the resize function") +//{ +// Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); +// Image img2 = Image::resize(img,make_tuple(200,300)); +// Mat img3 = imread("C:\\Users\\The user\\Desktop\\rest8.BMP"); +// Mat resizedImage; +// Size newSize(200,300); // Set the new size (width, height) +// resize(img3, resizedImage, newSize); +// +// bool same = true; +// +// for (int y = 0; y < resizedImage.rows; y++) +// { +// for (int x = 0; x < resizedImage.cols; x++) +// { +// Vec3b pixel = resizedImage.at(y, x); +// if (pixel[0] != img2.data[y * img2.width * 3 + x]) +// same = false; +// if (pixel[1] != img2.data[y * img2.width * 3 + x+1]) +// same = false; +// if (pixel[2] != img2.data[y * img2.width * 3 + x+2]) +// same = false; +// } +// } +// +// CHECK(same == true); +//} + +TEST_CASE("check the total function") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + CHECK(img.total() == 201588); +} + +TEST_CASE("check the getSize function") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + CHECK(img.getSize() == std::make_tuple(314, 214)); +} + +TEST_CASE("check the at function that return a specific channel with invalid argumant") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + CHECK_THROWS_AS(img.at(215, 1, 1), std::out_of_range); + CHECK_THROWS_AS(img.at(1, 314, 1), std::out_of_range); + CHECK_THROWS_AS(img.at(1, 1, 3), std::out_of_range); +} + +TEST_CASE("check the at function that return a specific channel") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + CHECK(img.at(1, 1, 1) == 230); + CHECK(img.at(213, 313, 2) == 38); + CHECK(img.at(100,100,1) == 121); +} + +TEST_CASE("check the at function that return the BGR of the pixel with invalid argumant") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + CHECK_THROWS_AS(img.at(215, 1), out_of_range); + CHECK_THROWS_AS(img.at(1, 314), out_of_range); +} + +TEST_CASE("check the at function that return the BGR of the pixel") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + vectorv{ 254,225,233 }; + vectorv2{ 42,36,38 }; + vectorv3{ 62,51,50 }; + auto res = img.at(0, 0); + auto res2 = img.at(213, 313); + auto res3 = img.at(103,145); + CHECK(res == v); + CHECK(res2 == v2); + CHECK(res3 == v3); +} + +TEST_CASE("check the operator== with other Image, with invalid argumant") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + Image img2 = Image::resize(img, make_tuple(100, 100)); + Image img3 = Image::resize(img, make_tuple(214, 100)); + CHECK_THROWS_AS(img == img2, exception); + CHECK_THROWS_AS(img==img3,exception); +} + +TEST_CASE("check the operator== with other Image") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + Image img2= Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + Image img3= Image::readImage("C:\\Users\\The user\\Desktop\\rest10.BMP"); + Image img4 = Image::resize(img3, make_tuple(img.width, img.height)); + + bool isSame = img == img2; + CHECK(isSame==true); + + isSame = img == img4; + CHECK(isSame != true); +} + +TEST_CASE("check the operator== with value") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + + bool isSame=img == 3; + bool res = true; + + for (int i = 0; i < img.width * img.height * img.channels; i++) + { + if (img.data[i] != 3) + res = false; + } + CHECK(isSame == res); +} + +TEST_CASE("check the operator+ with value, with invalid argumant") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + CHECK_THROWS_AS(img + 255, invalid_argument); +} + +TEST_CASE("check the operator+ with value") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + + Image img2 = img + 0; + bool res = true; + + for (int i = 0; i < img.width * img.height * img.channels; i++) + { + if (img.data[i]+0 != img2.data[i]) + res = false; + } + CHECK(res == true); +} + +TEST_CASE("check the operator- with value with invalid argumant") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + CHECK_THROWS_AS(img - 444, invalid_argument); +} + +TEST_CASE("check the operator- with value") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + + Image img2 = img - 3; + bool res = true; + + for (int i = 0; i < img.width * img.height * img.channels; i++) + { + if (img.data[i] - 3 != img2.data[i]) + res = false; + } + CHECK(res == true); +} + +TEST_CASE("check the operator= with other image") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + int refCount = *(img.refCount); + Image img2 = img; + + CHECK(img.data == img2.data); + CHECK(img.width == img2.width); + CHECK(img.height == img2.height); + CHECK(img.ROI == img2.ROI); + CHECK(img.channels == img2.channels); + CHECK(img.refCount == img2.refCount); + CHECK(*(img.refCount) == refCount+1); +} + +TEST_CASE("check the operator+ with other image, with invalid argumant") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + Image img2 = Image::readImage("C:\\Users\\The user\\Desktop\\rest10.BMP"); + CHECK_THROWS_AS(img + img2, invalid_argument); +} + +TEST_CASE("check the operator+ with other image in case they both have the same width") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + Image img2 = Image::readImage("C:\\Users\\The user\\Desktop\\rest10.BMP"); + Image img3 = Image::resize(img2, make_tuple(img.width, img2.height)); + Image resImage = img + img3; + bool res = true; + int imgSize = img.total(); + int resImgSize = resImage.total(); + for (int i = 0; i < resImgSize; i++) + { + if (i < imgSize) + { + if (resImage.data[i] != img.data[i]) + res = false; + } + else + { + if (resImage.data[i] != img3.data[i-imgSize]) + res = false; + } + + } + CHECK(res == true); +} + +TEST_CASE("check the operator+ with other image in case they both have the same height") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + Image img2 = Image::readImage("C:\\Users\\The user\\Desktop\\rest10.BMP"); + Image img3 = Image::resize(img2, make_tuple(img2.width, img.height)); + Image resImage = img + img3; + bool res = true; + int imgSize = img.total(); + int resImgSize = resImage.total(); + int imgRowSize = img.width * 3; + for (int i = 0; i < resImage.height; i++) + { + int toThisLine = i * resImage.width * 3; + for (int j = 0; j < img.width*3; j++) + { + if (resImage.data[toThisLine +j] != img.data[i*img.width*3+j]) + res = false; + } + for (int j = 0; j < img3.width * 3; j++) + { + if (resImage.data[toThisLine+img.width*3 + j] != img3.data[i * img3.width*3 + j]) + res = false; + } + } + CHECK(res == true); +} + +TEST_CASE("check the clone function") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + Image img2 = img.clone(); + + CHECK(img.data != img2.data); + CHECK(img.width == img2.width); + CHECK(img.height == img2.height); + CHECK(img.ROI == img2.ROI); + CHECK(img.channels == img2.channels); + CHECK(img.refCount != img2.refCount); + bool res = true; + + for (int i = 0; i < img.width * img.height * img.channels; i++) + { + if (img.data[i] != img2.data[i]) + res = false; + } + CHECK(res == true); +} + +TEST_CASE("check the empty function") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + Image img2(5, 5); + Image img3; + + CHECK(img.empty() == false); + CHECK(img2.empty() == true); + CHECK(img3.empty() == true); +} + +TEST_CASE("check the getData function") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + auto v = img.getData(); + bool res = true; + for (int i = 0; i < v.size(); i++) + { + if (v[i] != img.data[i]) + res = false; + } + CHECK(res== true); +} + +TEST_CASE("check the splitChannels function") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + Mat img2 = imread("C:\\Users\\The user\\Desktop\\rest8.BMP"); + auto v = img.splitChannels(); + vector channels; + split(img2, channels); + bool res = true; + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < v[0].size(); j++) + { + if (v[i][j] != channels[i].data[j]) + res = false; + } + } + CHECK(res == true); +} + +TEST_CASE("check the margeChannels function") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + auto v = img.splitChannels(); + auto v2 = Image::margeChannels(v); + bool res = true; + for (int i = 0; i < v2.size(); i++) + { + if (v2[i] != img.data[i]) + res = false; + } + CHECK(res == true); +} + +TEST_CASE("check the setAllPixel function with invalid argumant") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + vectorpixel = { 122,111,145 }; + + CHECK_THROWS_AS(img.setAllPixel(1, 314, pixel), invalid_argument); + CHECK_THROWS_AS(img.setAllPixel(214,1,pixel), invalid_argument); +} + +TEST_CASE("check the setAllPixel function") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + Image img2 = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + vectorpixel = { 255,0,0 }; + + img.setAllPixel(1, 1, pixel); + img.setAllPixel(213, 313, pixel); + img.setAllPixel(92, 39, pixel); + + auto v = img.at(1, 1); + auto v2=img2.at(1, 1); + bool same = v == v2; + bool sameV = v==pixel; + CHECK(same != true); + CHECK(sameV==true); + + v = img.at(213, 313); + v2 = img2.at(213, 313); + same = v == v2; + sameV = v == pixel; + CHECK(same != true); + CHECK(sameV == true); + + v = img.at(92, 39); + v2 = img2.at(92, 39); + same = v == v2; + sameV = v == pixel; + CHECK(same != true); + CHECK(sameV == true); +} + +TEST_CASE("check the setPixelCH function with invalid argumant") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + + CHECK_THROWS_AS(img.setPixelCH(1, 314, 3,2), invalid_argument); + CHECK_THROWS_AS(img.setPixelCH(214, 1, -1, 3), invalid_argument); + CHECK_THROWS_AS(img.setPixelCH(214, 1, 1, -3), invalid_argument); + CHECK_THROWS_AS(img.setPixelCH(214, 500, 1, -3), invalid_argument); + CHECK_THROWS_AS(img.setPixelCH(-214, 1, 1,-3), invalid_argument); +} + +TEST_CASE("check the setPixelCH function") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + Image img2 = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + + img.setPixelCH(1, 1, 0, 0); + img.setPixelCH(1, 1, 1, 0); + img.setPixelCH(1, 1, 2, 255); + + img.setPixelCH(95, 95, 0, 0); + img.setPixelCH(95, 95, 1, 0); + img.setPixelCH(95, 95, 2, 255); + + auto v = img.at(1, 1,1); + auto v2 = img2.at(1, 1,1); + bool same = v == v2; + bool sameC = v ==0; + + CHECK(same != true); + CHECK(sameC == true); + + v = img.at(95, 95,2); + v2 = img2.at(95, 95,2); + same = v == v2; + sameC = v == 255; + CHECK(same != true); + CHECK(sameC == true); +} + +TEST_CASE("check the row function with invalid argumant") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + + CHECK_THROWS_AS(img.row(500), invalid_argument); +} + +TEST_CASE("check the row function") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + + Image img2 = img.row(100); + + bool same = true; + + for (int i = 0; i < img.width*3; i++) + { + if (img.data[img.width*3*100+i] != img2.data[i]) + same = false; + } + + CHECK(same == true); +} + +TEST_CASE("check the col function with invalid argumant") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + + CHECK_THROWS_AS(img.col(314), invalid_argument); +} + +TEST_CASE("check the col function") +{ + Image img = Image::readImage("C:\\Users\\The user\\Desktop\\rest8.BMP"); + + Image img2 = img.col(100); + + bool same = true; + + for (int i = 0; i < img2.height; i++) + { + auto pixel = img.at(i, 100); + auto pixel2 = img2.at(i,0); + if (pixel == pixel2) + continue; + else + same = false; + } + + CHECK(same == true); +} + +//test on the ptr functions, resize waitKey \ No newline at end of file