823 lines
27 KiB
C++
823 lines
27 KiB
C++
// Dear ImGui: standalone example application for DirectX 11
|
||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||
|
||
#include "imgui.h"
|
||
#include "imgui_impl_win32.h"
|
||
#include "imgui_impl_dx11.h"
|
||
#include <d3d11.h>
|
||
#include <tchar.h>
|
||
#include "implot.h"
|
||
#include <array>
|
||
#define STB_IMAGE_IMPLEMENTATION
|
||
#include "stb_image.h"
|
||
|
||
static ID3D11Device* g_pd3dDevice = nullptr;
|
||
static ID3D11DeviceContext* g_pd3dDeviceContext = nullptr;
|
||
static IDXGISwapChain* g_pSwapChain = nullptr;
|
||
static ID3D11RenderTargetView* g_mainRenderTargetView = nullptr;
|
||
|
||
bool CreateDeviceD3D(HWND hWnd);
|
||
void CleanupDeviceD3D();
|
||
void CreateRenderTarget();
|
||
void CleanupRenderTarget();
|
||
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||
|
||
unsigned char* ImageData(const char* filename, int &width, int &height, int &channels)
|
||
{
|
||
unsigned char* image_data = stbi_load(filename, &width, &height, &channels, 4);
|
||
return image_data;
|
||
}
|
||
|
||
bool LoadTextureFromFile(unsigned char* image_data, int image_width, int image_height, ID3D11ShaderResourceView** out_srv)
|
||
{
|
||
D3D11_TEXTURE2D_DESC desc;
|
||
ZeroMemory(&desc, sizeof(desc));
|
||
desc.Width = image_width;
|
||
desc.Height = image_height;
|
||
desc.MipLevels = 1;
|
||
desc.ArraySize = 1;
|
||
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||
desc.SampleDesc.Count = 1;
|
||
desc.Usage = D3D11_USAGE_DEFAULT;
|
||
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||
desc.CPUAccessFlags = 0;
|
||
|
||
ID3D11Texture2D *pTexture = NULL;
|
||
D3D11_SUBRESOURCE_DATA subResource;
|
||
subResource.pSysMem = image_data;
|
||
subResource.SysMemPitch = desc.Width * 4;
|
||
subResource.SysMemSlicePitch = 0;
|
||
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
||
|
||
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
||
ZeroMemory(&srvDesc, sizeof(srvDesc));
|
||
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
||
srvDesc.Texture2D.MostDetailedMip = 0;
|
||
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, out_srv);
|
||
pTexture->Release();
|
||
|
||
return true;
|
||
}
|
||
|
||
#undef max;
|
||
#undef min;
|
||
#include <algorithm>
|
||
#include <iostream>
|
||
#include <cmath>
|
||
#include <vector>
|
||
|
||
// Funkcja dokonuj<75>ca dylacji
|
||
void dilation(const unsigned char* image, int width, int height, unsigned char* output) {
|
||
int structuringElement[3][3] = {
|
||
{0, 255, 0},
|
||
{255, 255, 255},
|
||
{0, 255, 0}
|
||
};
|
||
|
||
for (int y = 0; y < height; ++y) {
|
||
for (int x = 0; x < width; ++x) {
|
||
int maxPixelValue = 0;
|
||
for (int j = -1; j <= 1; ++j) {
|
||
for (int i = -1; i <= 1; ++i) {
|
||
if (x + i >= 0 && x + i < width && y + j >= 0 && y + j < height) {
|
||
int imagePixelValue = image[(y + j) * width + (x + i)];
|
||
int structuringElementValue = structuringElement[j + 1][i + 1];
|
||
int newPixelValue = imagePixelValue + structuringElementValue;
|
||
if (newPixelValue > maxPixelValue) {
|
||
maxPixelValue = newPixelValue;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
output[y * width + x] = static_cast<unsigned char>(maxPixelValue > 255 ? 255 : maxPixelValue);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Funkcja dokonuj<75>ca erozji
|
||
void erosion(const unsigned char* image, int width, int height, unsigned char* output) {
|
||
int structuringElement[3][3] = {
|
||
{0, 255, 0},
|
||
{255, 255, 255},
|
||
{0, 255, 0}
|
||
};
|
||
|
||
for (int y = 0; y < height; ++y) {
|
||
for (int x = 0; x < width; ++x) {
|
||
int minPixelValue = 255;
|
||
for (int j = -1; j <= 1; ++j) {
|
||
for (int i = -1; i <= 1; ++i) {
|
||
if (x + i >= 0 && x + i < width && y + j >= 0 && y + j < height) {
|
||
int imagePixelValue = image[(y + j) * width + (x + i)];
|
||
int structuringElementValue = structuringElement[j + 1][i + 1];
|
||
int newPixelValue = imagePixelValue - structuringElementValue;
|
||
if (newPixelValue < minPixelValue) {
|
||
minPixelValue = newPixelValue;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
output[y * width + x] = static_cast<unsigned char>(minPixelValue < 0 ? 0 : minPixelValue);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Funkcja dokonuj<75>ca hit-and-miss
|
||
void hitAndMiss(const unsigned char* image, int width, int height, unsigned char* output) {
|
||
int structuringElement1[3][3] = {
|
||
{0, 0, 0},
|
||
{255, 255, 0},
|
||
{0, 255, 0}
|
||
};
|
||
|
||
int structuringElement2[3][3] = {
|
||
{255, 255, 255},
|
||
{0, 0, 255},
|
||
{0, 0, 0}
|
||
};
|
||
|
||
for (int y = 0; y < height; ++y) {
|
||
for (int x = 0; x < width; ++x) {
|
||
bool match1 = true;
|
||
bool match2 = true;
|
||
for (int j = -1; j <= 1; ++j) {
|
||
for (int i = -1; i <= 1; ++i) {
|
||
if (x + i >= 0 && x + i < width && y + j >= 0 && y + j < height) {
|
||
int imagePixelValue = image[(y + j) * width + (x + i)];
|
||
int structuringElement1Value = structuringElement1[j + 1][i + 1];
|
||
int structuringElement2Value = structuringElement2[j + 1][i + 1];
|
||
if (structuringElement1Value == 255 && imagePixelValue != 255) {
|
||
match1 = false;
|
||
}
|
||
if (structuringElement2Value == 255 && imagePixelValue != 0) {
|
||
match2 = false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
output[y * width + x] = (match1 && match2) ? 255 : 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Funkcja dokonuj<75>ca pogrubiania
|
||
void thickening(const unsigned char* image, int width, int height, unsigned char* output) {
|
||
int structuringElement[3][3] = {
|
||
{0, 255, 0},
|
||
{255, 255, 255},
|
||
{0, 255, 0}
|
||
};
|
||
|
||
for (int y = 0; y < height; ++y) {
|
||
for (int x = 0; x < width; ++x) {
|
||
if (image[y * width + x] == 255) {
|
||
for (int j = -1; j <= 1; ++j) {
|
||
for (int i = -1; i <= 1; ++i) {
|
||
if (x + i >= 0 && x + i < width && y + j >= 0 && y + j < height) {
|
||
int structuringElementValue = structuringElement[j + 1][i + 1];
|
||
if (structuringElementValue == 255) {
|
||
output[(y + j) * width + (x + i)] = 255;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Funkcja dokonuj<75>ca pocieniania
|
||
void thinning(const unsigned char* image, int width, int height, unsigned char* output) {
|
||
int structuringElement[3][3] = {
|
||
{0, 255, 0},
|
||
{255, 255, 255},
|
||
{0, 255, 0}
|
||
};
|
||
|
||
for (int y = 0; y < height; ++y) {
|
||
for (int x = 0; x < width; ++x) {
|
||
if (image[y * width + x] == 255) {
|
||
bool match = true;
|
||
for (int j = -1; j <= 1; ++j) {
|
||
for (int i = -1; i <= 1; ++i) {
|
||
if (x + i >= 0 && x + i < width && y + j >= 0 && y + j < height) {
|
||
int imagePixelValue = image[(y + j) * width + (x + i)];
|
||
int structuringElementValue = structuringElement[j + 1][i + 1];
|
||
if (structuringElementValue == 255 && imagePixelValue != 255) {
|
||
match = false;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if (!match) {
|
||
break;
|
||
}
|
||
}
|
||
output[y * width + x] = match ? 255 : 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void rgbToHsl(float r, float g, float b, float &_h, float &_s, float &_l)
|
||
{
|
||
r /= 255.f;
|
||
g /= 255.f;
|
||
b /= 255.f;
|
||
float max = std::max({r, g, b});
|
||
float min = std::min({r, g, b});
|
||
float h, s, l = (max + min) / 2.f;
|
||
|
||
if(max - min < .001f)
|
||
{
|
||
h = s = 0.f;
|
||
}
|
||
else
|
||
{
|
||
float d = max - min;
|
||
s = l > 0.5f ? d / (2.f - max - min) : d / (max + min);
|
||
if (max - r < .001f)
|
||
{
|
||
h = (g - b) / d + (g < b ? 6.f : 0.f);
|
||
}
|
||
else if (max - g < .001f)
|
||
{
|
||
h = (b - r) / d + 2.f;
|
||
}
|
||
else if (max - b < .001f)
|
||
{
|
||
h = (r - g) / d + 4.f;
|
||
}
|
||
h /= 6;
|
||
}
|
||
|
||
_h = h;
|
||
_s = s;
|
||
_l = l;
|
||
}
|
||
|
||
void hslToRgb(float h, float s, float l, int &_r, int &_g, int &_b){
|
||
float r, g, b = 0.f;
|
||
|
||
if(s < .001f)
|
||
{
|
||
r = g = b = l;
|
||
}
|
||
else
|
||
{
|
||
auto hue2rgb = [](float p, float q, float t) {
|
||
if (t < 0) t += 1.f;
|
||
if (t > 1) t -= 1.f;
|
||
if (t < 1.f / 6.f) return p + (q - p) * 6.f * t;
|
||
if (t < 1.f / 2.f) return q;
|
||
if (t < 2.f / 3.f) return p + (q - p) * (2.f / 3.f - t) * 6.f;
|
||
return p;
|
||
};
|
||
|
||
float q = l < 0.5f ? l * (1.f + s) : l + s - l * s;
|
||
float p = 2.f * l - q;
|
||
r = hue2rgb(p, q, h + 1.f/3.f);
|
||
g = hue2rgb(p, q, h);
|
||
b = hue2rgb(p, q, h - 1.f/3.f);
|
||
}
|
||
|
||
_r = std::clamp(int(r * 255), 0, 255);
|
||
_g = std::clamp(int(g * 255), 0, 255);
|
||
_b = std::clamp(int(b * 255), 0, 255);
|
||
}
|
||
|
||
void InvertImageColors(unsigned char* imageData, int width, int height)
|
||
{
|
||
for (int y = 0; y < height; ++y)
|
||
{
|
||
for (int x = 0; x < width; ++x)
|
||
{
|
||
int index = (y * width + x) * 4;
|
||
imageData[index] = 255 - imageData[index];
|
||
imageData[index + 1] = 255 - imageData[index + 1];
|
||
imageData[index + 2] = 255 - imageData[index + 2];
|
||
}
|
||
}
|
||
}
|
||
|
||
void Sepia(unsigned char* imageData, int width, int height)
|
||
{
|
||
for (int y = 0; y < height; ++y)
|
||
{
|
||
for (int x = 0; x < width; ++x)
|
||
{
|
||
int index = (y * width + x) * 4;
|
||
imageData[index] = int(std::min((imageData[index] * .393f) + (imageData[index + 1] * .769f) + (imageData[index + 2] * .189f), 255.f));
|
||
imageData[index + 1] = int(std::min((imageData[index] * .349f) + (imageData[index + 1] * .686f) + (imageData[index + 2] * .168f), 255.f));
|
||
imageData[index + 2] = int(std::min((imageData[index] * .272f) + (imageData[index + 1] * .534f) + (imageData[index + 2] * .131f), 255.f));
|
||
}
|
||
}
|
||
}
|
||
|
||
void Saturation(unsigned char* imageData, int width, int height, float scale)
|
||
{
|
||
float h, s, l = 0.f;
|
||
|
||
for (int y = 0; y < height; ++y)
|
||
{
|
||
for (int x = 0; x < width; ++x)
|
||
{
|
||
int index = (y * width + x) * 4;
|
||
int r = imageData[index];
|
||
int b = imageData[index + 1];
|
||
int g = imageData[index + 2];
|
||
rgbToHsl(r, g, b, h, s, l);
|
||
s *= scale;
|
||
hslToRgb(h, s, l, r, g, b);
|
||
imageData[index] = r;
|
||
imageData[index + 1] = g;
|
||
imageData[index + 2] = b;
|
||
}
|
||
}
|
||
}
|
||
|
||
void Light(unsigned char* imageData, int width, int height, float scale)
|
||
{
|
||
float h, s, l = 0.f;
|
||
for (int y = 0; y < height; ++y)
|
||
{
|
||
for (int x = 0; x < width; ++x)
|
||
{
|
||
int index = (y * width + x) * 4;
|
||
int r = imageData[index];
|
||
int b = imageData[index + 1];
|
||
int g = imageData[index + 2];
|
||
rgbToHsl(r, g, b, h, s, l);
|
||
l *= scale;
|
||
hslToRgb(h, s, l, r, g, b);
|
||
imageData[index] = r;
|
||
imageData[index + 1] = g;
|
||
imageData[index + 2] = b;
|
||
}
|
||
}
|
||
}
|
||
|
||
std::array<std::array<float, 7>, 7> KernelFunction(float sigma)
|
||
{
|
||
const int kernel_size = 7;
|
||
std::array<std::array<float, 7>, 7> kernel;
|
||
float sum = 0.0f;
|
||
|
||
for (int i = 0; i < kernel_size; i++) {
|
||
for (int j = 0; j < kernel_size; j++) {
|
||
int x = i - kernel_size / 2;
|
||
int y = j - kernel_size / 2;
|
||
kernel[i][j] = exp(-(x * x + y * y) / (2 * sigma * sigma));
|
||
sum += kernel[i][j];
|
||
}
|
||
}
|
||
|
||
for (int i = 0; i < kernel_size; i++) {
|
||
for (int j = 0; j < kernel_size; j++) {
|
||
kernel[i][j] /= sum;
|
||
}
|
||
}
|
||
return kernel;
|
||
}
|
||
|
||
void GaussianKernel(unsigned char* imageData, int width, int height, int channels, int kernel_size, std::array<std::array<float, 7>, 7> kernel)
|
||
{
|
||
|
||
for (int y = 0; y < height; y++) {
|
||
for (int x = 0; x < width; x++) {
|
||
for (int c = 0; c < channels; c++) {
|
||
float sum = 0.0f;
|
||
for (int i = 0; i < kernel_size; i++) {
|
||
for (int j = 0; j < kernel_size; j++) {
|
||
int px = x + i - kernel_size / 2;
|
||
int py = y + j - kernel_size / 2;
|
||
if (px < 0 || px >= width || py < 0 || py >= height) {
|
||
continue;
|
||
}
|
||
sum += kernel[i][j] * imageData[(py * width + px) * channels + c];
|
||
}
|
||
}
|
||
imageData[(y * width + x) * channels + c] = (unsigned char)sum;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
unsigned char* greyScale(const unsigned char* image, unsigned char* grayscaleImage, int width, int height, int numChannels) {
|
||
for (int i = 0; i < width * height; ++i) {
|
||
unsigned char r = image[i * numChannels];
|
||
unsigned char g = image[i * numChannels + 1];
|
||
unsigned char b = image[i * numChannels + 2];
|
||
|
||
grayscaleImage[i] = static_cast<unsigned char>(0.2989 * r + 0.587 * g + 0.114 * b);
|
||
}
|
||
return grayscaleImage;
|
||
}
|
||
|
||
void binaryTransform(unsigned char* grayscaleImage, unsigned char* binaryImage, int width, int height, int threshold) {
|
||
for (int i = 0; i < width * height; ++i) {
|
||
binaryImage[i] = (grayscaleImage[i] > threshold) ? 255 : 0;
|
||
}
|
||
}
|
||
|
||
int calculateOtsuThreshold(const unsigned char* image, int width, int height) {
|
||
|
||
int histogram[256] = {0};
|
||
for (int i = 0; i < width * height; ++i) {
|
||
histogram[image[i]]++;
|
||
}
|
||
|
||
int totalPixels = width * height;
|
||
float sum = 0.0;
|
||
for (int i = 0; i < 256; ++i) {
|
||
sum += i * histogram[i];
|
||
}
|
||
|
||
float sumB = 0.0;
|
||
int wB = 0;
|
||
int wF = 0;
|
||
float maxVariance = 0.0;
|
||
int threshold = 0;
|
||
|
||
for (int i = 0; i < 256; ++i) {
|
||
wB += histogram[i];
|
||
if (wB == 0) continue;
|
||
|
||
wF = totalPixels - wB;
|
||
if (wF == 0) break;
|
||
|
||
sumB += i * histogram[i];
|
||
|
||
float meanB = sumB / wB;
|
||
float meanF = (sum - sumB) / wF;
|
||
|
||
float betweenVariance = wB * wF * (meanB - meanF) * (meanB - meanF);
|
||
|
||
if (betweenVariance > maxVariance) {
|
||
maxVariance = betweenVariance;
|
||
threshold = i;
|
||
}
|
||
}
|
||
|
||
return threshold;
|
||
}
|
||
|
||
void hough_transform(unsigned char* input_image, int width, int height, int threshold)
|
||
{
|
||
int hough_width = 2 * (width + height);
|
||
int hough_height = 180;
|
||
int* hough_space = new int[hough_width * hough_height]();
|
||
|
||
for (int y = 0; y < height; y++)
|
||
{
|
||
for (int x = 0; x < width; x++)
|
||
{
|
||
if (input_image[(y * width + x)] > threshold)
|
||
{
|
||
for (int theta = 0; theta < hough_height; theta++)
|
||
{
|
||
double angle = theta * (3.14 / 180.0);
|
||
int rho = static_cast<int>((x * cos(angle)) + (y * sin(angle)));
|
||
rho += (hough_width / 2);
|
||
hough_space[(theta * hough_width) + rho]++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
int max_value = 0;
|
||
for (int i = 0; i < hough_width * hough_height; i++)
|
||
{
|
||
if (hough_space[i] > max_value)
|
||
{
|
||
max_value = hough_space[i];
|
||
}
|
||
}
|
||
|
||
unsigned char* hough_image = new unsigned char[hough_width * hough_height * 3]();
|
||
for (int y = 0; y < hough_height; y++)
|
||
{
|
||
for (int x = 0; x < hough_width; x++)
|
||
{
|
||
int value = static_cast<int>(255.0 * hough_space[(y * hough_width) + x] / max_value);
|
||
hough_image[3 * (y * hough_width + x)] = value;
|
||
hough_image[3 * (y * hough_width + x) + 1] = value;
|
||
hough_image[3 * (y * hough_width + x) + 2] = value;
|
||
}
|
||
}
|
||
}
|
||
|
||
int main(int, char**)
|
||
{
|
||
WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr };
|
||
::RegisterClassExW(&wc);
|
||
HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX11 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, nullptr, nullptr, wc.hInstance, nullptr);
|
||
|
||
if (!CreateDeviceD3D(hwnd))
|
||
{
|
||
CleanupDeviceD3D();
|
||
::UnregisterClassW(wc.lpszClassName, wc.hInstance);
|
||
return 1;
|
||
}
|
||
|
||
::ShowWindow(hwnd, SW_SHOWDEFAULT);
|
||
::UpdateWindow(hwnd);
|
||
|
||
IMGUI_CHECKVERSION();
|
||
ImGui::CreateContext();
|
||
ImPlot::CreateContext();
|
||
//ImPlot::CreateContext();
|
||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
|
||
|
||
ImGui::StyleColorsDark();
|
||
|
||
ImGui_ImplWin32_Init(hwnd);
|
||
ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
|
||
|
||
bool main_window = true;
|
||
bool show_another_window = false;
|
||
bool image_window = false;
|
||
bool histogram = false;
|
||
char image_location[MAX_PATH] = {};
|
||
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
|
||
|
||
bool negative = false;
|
||
bool sepia = false;
|
||
bool saturation = false;
|
||
bool blure = false;
|
||
float scaleS = 0.f;
|
||
bool light = false;
|
||
float scaleL = 0.f;
|
||
float sigma = 2.0f;
|
||
bool binary = false;
|
||
bool hough = false;
|
||
|
||
bool done = false;
|
||
|
||
int* colorR = nullptr;
|
||
int* colorG = nullptr;
|
||
int* colorB = nullptr;
|
||
|
||
while (!done)
|
||
{
|
||
MSG msg;
|
||
while (::PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE))
|
||
{
|
||
::TranslateMessage(&msg);
|
||
::DispatchMessage(&msg);
|
||
if (msg.message == WM_QUIT)
|
||
done = true;
|
||
}
|
||
if (done)
|
||
break;
|
||
|
||
ImGui_ImplDX11_NewFrame();
|
||
ImGui_ImplWin32_NewFrame();
|
||
ImGui::NewFrame();
|
||
|
||
if (main_window)
|
||
{
|
||
static float f = 0.0f;
|
||
static int counter = 0;
|
||
|
||
ImGui::Begin("App");
|
||
ImGui::InputText("Image location", image_location, sizeof(image_location), image_window ? ImGuiInputTextFlags_ReadOnly : 0);
|
||
|
||
if (!image_window)
|
||
{
|
||
if (ImGui::Button("Load Image"))
|
||
image_window = true;
|
||
}
|
||
else
|
||
{
|
||
if (ImGui::Button("Close Image"))
|
||
image_window = false;
|
||
|
||
if (colorR != NULL && colorB != NULL && colorG != NULL)
|
||
{
|
||
delete[] colorR;
|
||
delete[] colorG;
|
||
delete[] colorB;
|
||
|
||
colorR = NULL;
|
||
colorG = NULL;
|
||
colorB = NULL;
|
||
}
|
||
}
|
||
ImGui::End();
|
||
}
|
||
|
||
if (histogram)
|
||
{
|
||
ImGui::Begin("Histogram");
|
||
|
||
ImGui::End();
|
||
}
|
||
|
||
if (image_window)
|
||
{
|
||
int my_image_width = 0;
|
||
int my_image_height = 0;
|
||
int my_image_channels = 0;
|
||
unsigned char* image_data = ImageData(image_location, my_image_width, my_image_height, my_image_channels);
|
||
unsigned char* grayscaleImage = new unsigned char[my_image_width * my_image_height];
|
||
unsigned char* binaryImage = new unsigned char[my_image_width * my_image_height];
|
||
if (colorR == NULL && colorB == NULL && colorG == NULL) {
|
||
colorR = new int[my_image_width * my_image_height];
|
||
colorG = new int[my_image_width * my_image_height];
|
||
colorB = new int[my_image_width * my_image_height];
|
||
|
||
int place = 0;
|
||
|
||
for (int y = 0; y < my_image_height; ++y)
|
||
{
|
||
for (int x = 0; x < my_image_width; ++x)
|
||
{
|
||
int index = (y * my_image_width + x) * 4;
|
||
|
||
colorR[place] = image_data[index];
|
||
colorG[place] = image_data[index + 1];
|
||
colorB[place++] = image_data[index + 2];
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
if (negative)
|
||
{
|
||
InvertImageColors(image_data, my_image_width, my_image_height);
|
||
}
|
||
if (sepia)
|
||
{
|
||
Sepia(image_data, my_image_width, my_image_height);
|
||
}
|
||
if (saturation)
|
||
{
|
||
Saturation(image_data, my_image_width, my_image_height, scaleS);
|
||
}
|
||
if (light)
|
||
{
|
||
Light(image_data, my_image_width, my_image_height, scaleL);
|
||
}
|
||
if (blure)
|
||
{
|
||
GaussianKernel(image_data, my_image_width, my_image_height, my_image_channels, 7, KernelFunction(sigma));
|
||
}
|
||
if (binary)
|
||
{
|
||
binaryTransform(greyScale(image_data, grayscaleImage, my_image_width, my_image_height, my_image_channels), binaryImage, my_image_width, my_image_height, calculateOtsuThreshold(image_data, my_image_width, my_image_height));
|
||
}
|
||
if (hough)
|
||
{
|
||
hough_transform(image_data, my_image_width, my_image_height, calculateOtsuThreshold(image_data, my_image_width, my_image_height));
|
||
}
|
||
if (!image_data)
|
||
{
|
||
ImGui::Begin("Error");
|
||
ImGui::Text("Wrong path");
|
||
if (ImGui::Button("Ok"))
|
||
image_window = false;
|
||
ImGui::End();
|
||
}
|
||
else
|
||
{
|
||
ID3D11ShaderResourceView* my_texture = NULL;
|
||
if (binary == TRUE) {
|
||
bool ret = LoadTextureFromFile(binaryImage, my_image_width, my_image_height, &my_texture);
|
||
stbi_image_free(binaryImage);
|
||
stbi_image_free(grayscaleImage);
|
||
stbi_image_free(image_data);
|
||
}
|
||
else {
|
||
bool ret = LoadTextureFromFile(image_data, my_image_width, my_image_height, &my_texture);
|
||
stbi_image_free(image_data);
|
||
}
|
||
ImGui::Begin("Image window");
|
||
ImGui::Image((void*)my_texture, ImVec2(my_image_width, my_image_height));
|
||
ImGui::End();
|
||
ImGui::Begin("Filters");
|
||
ImGui::Checkbox("Histogram", &histogram);
|
||
ImGui::Checkbox("Negative", &negative);
|
||
ImGui::Checkbox("Sepia", &sepia);
|
||
ImGui::Checkbox("Saturation", &saturation);
|
||
ImGui::SameLine();
|
||
ImGui::SliderFloat(" ", &scaleS, 0.f, 1.f);
|
||
ImGui::Checkbox("Light", &light);
|
||
ImGui::SameLine();
|
||
ImGui::SliderFloat(" ", &scaleL, 0.f, 1.f);
|
||
ImGui::Checkbox("Blure", &blure);
|
||
ImGui::SameLine();
|
||
ImGui::SliderFloat(" ", &sigma, 0.f, 10.f);
|
||
ImGui::Checkbox("Binaryzacja", &binary);
|
||
ImGui::Checkbox("Hough transform", &hough);
|
||
ImGui::End();
|
||
}
|
||
}
|
||
|
||
ImGui::Render();
|
||
const float clear_color_with_alpha[4] = { clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w };
|
||
g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, nullptr);
|
||
g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha);
|
||
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
|
||
|
||
g_pSwapChain->Present(1, 0);
|
||
}
|
||
|
||
ImGui_ImplDX11_Shutdown();
|
||
ImGui_ImplWin32_Shutdown();
|
||
ImPlot::DestroyContext();
|
||
ImGui::DestroyContext();
|
||
|
||
CleanupDeviceD3D();
|
||
::DestroyWindow(hwnd);
|
||
::UnregisterClassW(wc.lpszClassName, wc.hInstance);
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
bool CreateDeviceD3D(HWND hWnd)
|
||
{
|
||
DXGI_SWAP_CHAIN_DESC sd;
|
||
ZeroMemory(&sd, sizeof(sd));
|
||
sd.BufferCount = 2;
|
||
sd.BufferDesc.Width = 0;
|
||
sd.BufferDesc.Height = 0;
|
||
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||
sd.BufferDesc.RefreshRate.Numerator = 60;
|
||
sd.BufferDesc.RefreshRate.Denominator = 1;
|
||
sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
|
||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||
sd.OutputWindow = hWnd;
|
||
sd.SampleDesc.Count = 1;
|
||
sd.SampleDesc.Quality = 0;
|
||
sd.Windowed = TRUE;
|
||
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||
|
||
UINT createDeviceFlags = 0;
|
||
D3D_FEATURE_LEVEL featureLevel;
|
||
const D3D_FEATURE_LEVEL featureLevelArray[2] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, };
|
||
HRESULT res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext);
|
||
if (res == DXGI_ERROR_UNSUPPORTED)
|
||
res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext);
|
||
if (res != S_OK)
|
||
return false;
|
||
|
||
CreateRenderTarget();
|
||
return true;
|
||
}
|
||
|
||
void CleanupDeviceD3D()
|
||
{
|
||
CleanupRenderTarget();
|
||
if (g_pSwapChain) { g_pSwapChain->Release(); g_pSwapChain = nullptr; }
|
||
if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = nullptr; }
|
||
if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = nullptr; }
|
||
}
|
||
|
||
void CreateRenderTarget()
|
||
{
|
||
ID3D11Texture2D* pBackBuffer;
|
||
g_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
||
g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &g_mainRenderTargetView);
|
||
pBackBuffer->Release();
|
||
}
|
||
|
||
void CleanupRenderTarget()
|
||
{
|
||
if (g_mainRenderTargetView) { g_mainRenderTargetView->Release(); g_mainRenderTargetView = nullptr; }
|
||
}
|
||
|
||
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||
|
||
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||
{
|
||
if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
|
||
return true;
|
||
|
||
switch (msg)
|
||
{
|
||
case WM_SIZE:
|
||
if (g_pd3dDevice != nullptr && wParam != SIZE_MINIMIZED)
|
||
{
|
||
CleanupRenderTarget();
|
||
g_pSwapChain->ResizeBuffers(0, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam), DXGI_FORMAT_UNKNOWN, 0);
|
||
CreateRenderTarget();
|
||
}
|
||
return 0;
|
||
case WM_SYSCOMMAND:
|
||
if ((wParam & 0xfff0) == SC_KEYMENU)
|
||
return 0;
|
||
break;
|
||
case WM_DESTROY:
|
||
::PostQuitMessage(0);
|
||
return 0;
|
||
}
|
||
return ::DefWindowProcW(hWnd, msg, wParam, lParam);
|
||
}
|