removed subdirectories

This commit is contained in:
Lauchmelder 2022-01-26 17:38:42 +01:00
parent ab40eeb4e2
commit b4db34fda3
6 changed files with 3 additions and 429 deletions

4
.gitignore vendored
View file

@ -1,2 +1,4 @@
bin/ bin/
.vscode/ html/
latex/
.vscode/

View file

@ -1,102 +0,0 @@
#pragma once
#include <vector>
#include <string>
#include <cstdint>
#include <fstream>
/**
* @brief Stores PGM image data
*
* This class can read and write PGM images, perform smoothing and
* edge detection on them and display them in the console as ASCII art
*/
class Bild
{
public:
// ASCII characters used when printing the image to stdout
static const std::string asciiBrightnessMap;
public:
/**
* @brief Creates a new empty picture.
*
* The created picture has no dimensions and contains no pixel data.
*/
Bild() = default;
/**
* @brief Construct a new empty picture with meta data
*
* The pixel buffer will be empty, but the meta data (width, height, description)
* will be set, and the pixel buffer will be resized to match the dimensions
*
* @param width Width of the image
* @param height Height of the image
* @param description Description of the image
*/
Bild(uint32_t width, uint32_t height, const std::string& description);
/**
* @brief Copy an image
*
* The copy will copy the image data from the original image to a new buffer
*
* @param other The image to copy from
*/
Bild(const Bild& other) = default;
/**
* @brief Load an image
*
* Reads a file containing image data and populates the pixel array
*
* @param file (Valid) filestream containing image data
* @param image The image object to store the data in
* @return The modified filestream
*/
friend std::ifstream& operator>>(std::ifstream& file, Bild& image);
/**
* @brief Save an image
*
* Writes the stored image data into a file, overwriting any contents in it
*
* @param file (Valid) filestream to store the image in
* @param image The image object to get the data from
* @return The modified filestream
*/
friend std::ofstream& operator<<(std::ofstream& file, const Bild& image);
/**
* @brief Renders the image to the console
*
* Draws the image in the console using ascii characters.
* Das war zwar in der Aufgabe nicht verlangt aber ich wollte gern die Bilder sehen
*
* @param os Output stream to draw to
* @param image Image to draw
* @return The modified output stream
*/
friend std::ostream& operator<<(std::ostream& os, const Bild& image);
/**
* @brief Applies smoothing to an image, effectively blurring it
*
* @return The blurred image
*/
Bild Geglaettet() const;
/**
* @brief Performs edge detection on the image
*
* @return An image with only the edges found in the original
*/
Bild Kantenbild() const;
private:
uint32_t width {};
uint32_t height {};
std::string description;
std::vector<uint8_t> pixels;
};

View file

@ -1,183 +0,0 @@
#include "bild.hpp"
#include <iostream>
#include <sstream>
const std::string Bild::asciiBrightnessMap = ".'`^\",:;Il!i><~+_-?][}{1)(|\\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$";
Bild::Bild(uint32_t width, uint32_t height, const std::string& description) :
width(width), height(height), description(description)
{
pixels.resize(width * height);
}
std::ifstream& operator>>(std::ifstream& file, Bild& image)
{
std::string lineContent;
// First line should contain "P2"
std::getline(file, lineContent);
if(lineContent[0] != 'P' || lineContent[1] != '2')
{
throw std::runtime_error("Missing/Wrong PGM magic number.");
}
// The second line contains an image description
std::getline(file, lineContent);
std::string::iterator it;
for(it = lineContent.begin(); it != lineContent.end(); it++) // Flush out any leading spaces to get the description
{
if(*it != ' ' && *it != '#') // Break from loop if the iterator reached a character that isnt '#' or ' '
break;
}
image.description = std::string(it, lineContent.end() - 1); // Store the description (and cut off the newline)
// The third line contains the image dimensions
file >> image.width >> image.height;
std::getline(file, lineContent);
// The fourth line contains the max brightness value
std::getline(file, lineContent); // Do nothing with it
// The remaining file contains image data
uint16_t pixelValue = 0;
while(std::getline(file, lineContent)) // Loop through remaining lines
{
std::stringstream ss(lineContent);
while(ss >> pixelValue) // Loop through numbers in the line
{
image.pixels.push_back(static_cast<uint8_t>(pixelValue)); // Write pixel into the array
}
}
// Check if vector size matches image dimensions
if(image.pixels.size() != static_cast<size_t>(image.width) * image.height)
{
throw std::runtime_error(
"Amount of image data doesn't match image dimensions. Expected " +
std::to_string(image.width * image.height) +
" pixels, got " + std::to_string(image.pixels.size()) +
" pixels instead."
);
}
return file;
}
std::ofstream& operator<<(std::ofstream& file, const Bild& image)
{
file << "P2" << std::endl; // Write magic number to file
file << "# " << image.description << std::endl; // Write image description
file << image.width << " " << image.height << std::endl; // Write image dimensions
file << 255 << std::endl; // Write max brightness value
// Write pixel data
std::string line;
for(uint8_t pixel : image.pixels)
{
uint32_t value = static_cast<uint32_t>(pixel);
// If the current line would become longer than 70 characters, write the line to
// the file, insert a newline and clear the line
if(line.size() + std::to_string(value).length() > 70)
{
file << line << std::endl;
line.clear();
}
line += std::to_string(value) + " ";
}
// Write remaining lines to file
file << line << std::endl;
return file;
}
std::ostream& operator<<(std::ostream& os, const Bild& image)
{
// Loop over pixels in image
for(uint16_t y = 0; y < image.height; y++)
{
std::stringstream lineBuffer;
for(uint16_t x = 0; x < image.width; x++)
{
uint8_t brightness = image.pixels[y * image.width + x];
// Map the pixel brightness (which is in the interval [0, 255]) to the ascii chart length
uint8_t asciiMapIndex = static_cast<uint8_t>(brightness * (Bild::asciiBrightnessMap.length() - 1) / 255);
lineBuffer << Bild::asciiBrightnessMap[asciiMapIndex];
}
std::cout << lineBuffer.str() << std::endl;
}
return os;
}
Bild Bild::Geglaettet() const
{
// Create new image with same dimensions
Bild smoothedImage(width, height, description + " smoothed");
// Apply smoothing
for(uint32_t y = 0; y < smoothedImage.height; y++)
{
for(uint32_t x = 0; x < smoothedImage.width; x++)
{
// If this is a border pixel just copy it from the original
if(y == 0 || x == 0 || y == smoothedImage.height - 1 || x == smoothedImage.width - 1)
{
smoothedImage.pixels[y * smoothedImage.width + x] = pixels[y * smoothedImage.width + x];
continue;
}
// Else, make this pixel the average of its 4 neighbours
uint32_t sumOfPixels =
pixels[(y - 1) * smoothedImage.width + (x + 0)] +
pixels[(y + 1) * smoothedImage.width + (x + 0)] +
pixels[(y + 0) * smoothedImage.width + (x - 1)] +
pixels[(y + 0) * smoothedImage.width + (x + 1)] +
4 * pixels[y * smoothedImage.width + x];
smoothedImage.pixels[y * smoothedImage.width + x] = static_cast<uint8_t>(sumOfPixels / 8);
}
}
return smoothedImage;
}
Bild Bild::Kantenbild() const
{
// Create new image and copy metadata
Bild modifiedImage(width, height, description + " edged");
// Apply edge detection
for(uint32_t y = 0; y < modifiedImage.height; y++)
{
for(uint32_t x = 0; x < modifiedImage.width; x++)
{
// If this is a border pixel set its brightness to 0
if(y == 0 || x == 0 || y == modifiedImage.height - 1 || x == modifiedImage.width - 1)
{
modifiedImage.pixels[y * modifiedImage.width + x] = 0;
continue;
}
// Else, apply the formula to calculate pixel brightness
int32_t sumOfPixels =
pixels[(y - 1) * modifiedImage.width + (x + 0)] +
pixels[(y + 1) * modifiedImage.width + (x + 0)] +
pixels[(y + 0) * modifiedImage.width + (x - 1)] +
pixels[(y + 0) * modifiedImage.width + (x + 1)] -
4 * pixels[y * modifiedImage.width + x];
if(sumOfPixels < 0)
sumOfPixels = 0;
modifiedImage.pixels[y * modifiedImage.width + x] = static_cast<uint8_t>(sumOfPixels / 8);
}
}
return modifiedImage;
}

View file

@ -1,48 +0,0 @@
/**
* Reads a PGM file and performs edge detection, then writes the result to disk
*/
#include <iostream>
#include "bild.hpp"
int main(int argc, char** argv)
{
if(argc < 2)
{
std::cout << "Usage: edetect <pgm file>" << std::endl;
return 0;
}
std::string filename = argv[1];
// Load file
std::ifstream file(filename);
if(!file.good())
{
std::cerr << "Failed to open file" << std::endl;
return -1;
}
// Create image
Bild image;
try
{
file >> image;
}
catch(const std::runtime_error& err)
{
std::cerr << err.what() << std::endl;
file.close();
return -1;
}
file.close();
// Print image
image = image.Kantenbild();
filename.insert(filename.find('.'), "_modified");
std::ofstream outFile(filename);
outFile << image;
outFile.close();
return 0;
}

View file

@ -1,42 +0,0 @@
/**
* Displays a given PGM image in the console using ASCII characters
*/
#include <iostream>
#include "bild.hpp"
int main(int argc, char** argv)
{
// If there are no additional arguments print usage info
if(argc < 2)
{
std::cout << "Usage: imageviewer <pgm file>" << std::endl;
return 0;
}
// Load file
std::ifstream file(argv[1]);
if(!file.good())
{
std::cerr << "Failed to open file" << std::endl;
return -1;
}
// Create image
Bild image;
try
{
file >> image;
}
catch(const std::runtime_error& err)
{
std::cerr << err.what() << std::endl;
file.close();
return -1;
}
file.close();
// Print image
std::cout << image << std::endl;
return 0;
}

View file

@ -1,53 +0,0 @@
/**
* Reads a PGM image and smooths it by some amount, then writes it back to disk
*/
#include <iostream>
#include "bild.hpp"
int main(int argc, char** argv)
{
if(argc < 2)
{
std::cout << "Usage: smooth <pgm file>" << std::endl;
return 0;
}
std::string filename = argv[1];
uint16_t smoothing;
std::cout << "Wie oft soll das Bild geglaettet werden? ";
std::cin >> smoothing;
// Load file
std::ifstream file(filename);
if(!file.good())
{
std::cerr << "Failed to open file" << std::endl;
return -1;
}
// Create image
Bild image;
try
{
file >> image;
}
catch(const std::runtime_error& err)
{
std::cerr << err.what() << std::endl;
file.close();
return -1;
}
file.close();
// Print image
for(uint8_t i = 0; i < smoothing; i++)
image = image.Geglaettet();
filename.insert(filename.find('.'), "_modified");
std::ofstream outFile(filename);
outFile << image;
outFile.close();
return 0;
}