kopia lustrzana https://github.com/joshua-jerred/SSTV-Image-Tools
Additional text overlay
rodzic
6e405edc0f
commit
014352be17
|
@ -1 +1 @@
|
||||||
{"total":15240,"sessions":[{"begin":"2023-03-12T13:44:37-06:00","end":"2023-03-12T13:48:55-06:00","duration":258},{"begin":"2023-03-12T13:49:38-06:00","end":"2023-03-12T13:55:19-06:00","duration":341},{"begin":"2023-03-12T13:55:28-06:00","end":"2023-03-12T14:12:39-06:00","duration":1030},{"begin":"2023-03-12T14:12:42-06:00","end":"2023-03-12T14:53:07-06:00","duration":2424},{"begin":"2023-03-12T14:56:47-06:00","end":"2023-03-12T15:03:52-06:00","duration":425},{"begin":"2023-03-12T15:05:24-06:00","end":"2023-03-12T15:32:37-06:00","duration":1632},{"begin":"2023-03-12T15:32:42-06:00","end":"2023-03-12T15:48:18-06:00","duration":936},{"begin":"2023-03-12T15:49:19-06:00","end":"2023-03-12T15:59:42-06:00","duration":623},{"begin":"2023-03-12T16:00:06-06:00","end":"2023-03-12T16:07:04-06:00","duration":417},{"begin":"2023-03-12T16:07:33-06:00","end":"2023-03-12T16:13:28-06:00","duration":354},{"begin":"2023-03-12T16:17:33-06:00","end":"2023-03-12T16:36:24-06:00","duration":1131},{"begin":"2023-03-12T16:38:20-06:00","end":"2023-03-12T17:24:24-06:00","duration":2764},{"begin":"2023-03-12T17:25:18-06:00","end":"2023-03-12T17:27:19-06:00","duration":121},{"begin":"2023-03-12T18:08:42-06:00","end":"2023-03-12T18:08:57-06:00","duration":15},{"begin":"2023-03-12T18:09:00-06:00","end":"2023-03-12T18:11:02-06:00","duration":122},{"begin":"2023-03-12T19:14:25-06:00","end":"2023-03-12T19:17:15-06:00","duration":170},{"begin":"2023-03-12T19:18:33-06:00","end":"2023-03-12T19:20:50-06:00","duration":137},{"begin":"2023-03-12T19:21:10-06:00","end":"2023-03-12T19:24:03-06:00","duration":173},{"begin":"2023-03-12T19:25:08-06:00","end":"2023-03-12T19:33:11-06:00","duration":483},{"begin":"2023-03-12T19:35:37-06:00","end":"2023-03-12T19:37:53-06:00","duration":135},{"begin":"2023-03-12T19:39:51-06:00","end":"2023-03-12T19:41:53-06:00","duration":122},{"begin":"2023-03-12T19:48:10-06:00","end":"2023-03-12T20:11:58-06:00","duration":1427}]}
|
{"total":17589,"sessions":[{"begin":"2023-03-12T13:44:37-06:00","end":"2023-03-12T13:48:55-06:00","duration":258},{"begin":"2023-03-12T13:49:38-06:00","end":"2023-03-12T13:55:19-06:00","duration":341},{"begin":"2023-03-12T13:55:28-06:00","end":"2023-03-12T14:12:39-06:00","duration":1030},{"begin":"2023-03-12T14:12:42-06:00","end":"2023-03-12T14:53:07-06:00","duration":2424},{"begin":"2023-03-12T14:56:47-06:00","end":"2023-03-12T15:03:52-06:00","duration":425},{"begin":"2023-03-12T15:05:24-06:00","end":"2023-03-12T15:32:37-06:00","duration":1632},{"begin":"2023-03-12T15:32:42-06:00","end":"2023-03-12T15:48:18-06:00","duration":936},{"begin":"2023-03-12T15:49:19-06:00","end":"2023-03-12T15:59:42-06:00","duration":623},{"begin":"2023-03-12T16:00:06-06:00","end":"2023-03-12T16:07:04-06:00","duration":417},{"begin":"2023-03-12T16:07:33-06:00","end":"2023-03-12T16:13:28-06:00","duration":354},{"begin":"2023-03-12T16:17:33-06:00","end":"2023-03-12T16:36:24-06:00","duration":1131},{"begin":"2023-03-12T16:38:20-06:00","end":"2023-03-12T17:24:24-06:00","duration":2764},{"begin":"2023-03-12T17:25:18-06:00","end":"2023-03-12T17:27:19-06:00","duration":121},{"begin":"2023-03-12T18:08:42-06:00","end":"2023-03-12T18:08:57-06:00","duration":15},{"begin":"2023-03-12T18:09:00-06:00","end":"2023-03-12T18:11:02-06:00","duration":122},{"begin":"2023-03-12T19:14:25-06:00","end":"2023-03-12T19:17:15-06:00","duration":170},{"begin":"2023-03-12T19:18:33-06:00","end":"2023-03-12T19:20:50-06:00","duration":137},{"begin":"2023-03-12T19:21:10-06:00","end":"2023-03-12T19:24:03-06:00","duration":173},{"begin":"2023-03-12T19:25:08-06:00","end":"2023-03-12T19:33:11-06:00","duration":483},{"begin":"2023-03-12T19:35:37-06:00","end":"2023-03-12T19:37:53-06:00","duration":135},{"begin":"2023-03-12T19:39:51-06:00","end":"2023-03-12T19:41:53-06:00","duration":122},{"begin":"2023-03-12T19:48:10-06:00","end":"2023-03-12T20:11:58-06:00","duration":1427},{"begin":"2023-03-15T19:53:49-06:00","end":"2023-03-15T20:08:22-06:00","duration":873},{"begin":"2023-03-15T20:08:26-06:00","end":"2023-03-15T20:33:02-06:00","duration":1476}]}
|
Plik binarny nie jest wyświetlany.
Przed Szerokość: | Wysokość: | Rozmiar: 24 KiB Po Szerokość: | Wysokość: | Rozmiar: 48 KiB |
Plik binarny nie jest wyświetlany.
Przed Szerokość: | Wysokość: | Rozmiar: 25 KiB Po Szerokość: | Wysokość: | Rozmiar: 39 KiB |
Plik binarny nie jest wyświetlany.
Przed Szerokość: | Wysokość: | Rozmiar: 6.2 KiB Po Szerokość: | Wysokość: | Rozmiar: 37 KiB |
|
@ -8,10 +8,19 @@ int main() {
|
||||||
std::array<std::string, 3> test_images = {"test1.png", "test2.png",
|
std::array<std::string, 3> test_images = {"test1.png", "test2.png",
|
||||||
"test3.jpg"};
|
"test3.jpg"};
|
||||||
|
|
||||||
for (auto &image_path : test_images) {
|
std::vector<std::string> data = {"PRES 1025mb", "TEMP 25.0c",
|
||||||
|
"HUMID 50%", "ALT 102416ft" };
|
||||||
|
|
||||||
|
std::vector<std::string> data2 = {"TESTING"};
|
||||||
|
|
||||||
|
for (auto &image_path : test_images) { // Do this for each image
|
||||||
SstvImage image(SstvImage::Mode::ROBOT_36_COLOR, image_path,
|
SstvImage image(SstvImage::Mode::ROBOT_36_COLOR, image_path,
|
||||||
"converted_" + image_path);
|
"converted_" + image_path);
|
||||||
|
|
||||||
image.AddCallSign("N0CALL");
|
image.AddCallSign("N0CALL");
|
||||||
|
image.AddText(data);
|
||||||
|
image.AddText(data2, false, SstvImage::Color(0, 0, 0), SstvImage::Color(1, 1, 1));
|
||||||
|
image.AdjustColors(); // Optional, needed if getting rgb pixel values
|
||||||
|
|
||||||
SstvImage::Pixel pixel;
|
SstvImage::Pixel pixel;
|
||||||
if (!image.GetPixel(128, 91, pixel)) {
|
if (!image.GetPixel(128, 91, pixel)) {
|
||||||
|
|
|
@ -9,24 +9,26 @@
|
||||||
|
|
||||||
class SstvImage {
|
class SstvImage {
|
||||||
public:
|
public:
|
||||||
enum class Mode {
|
enum class Mode {
|
||||||
ROBOT_8_BW, // 160x120 (4:3) Black and White
|
ROBOT_8_BW, // 160x120 (4:3) Black and White
|
||||||
ROBOT_12_BW, // 160x120 (4:3) Black and White
|
ROBOT_12_BW, // 160x120 (4:3) Black and White
|
||||||
ROBOT_24_BW, // 320x240 (4:3) Black and White
|
ROBOT_24_BW, // 320x240 (4:3) Black and White
|
||||||
ROBOT_36_BW, // 320x240 (4:3) Black and White
|
ROBOT_36_BW, // 320x240 (4:3) Black and White
|
||||||
ROBOT_12_COLOR, // 160x120 (4:3) Color
|
ROBOT_12_COLOR, // 160x120 (4:3) Color
|
||||||
ROBOT_24_COLOR, // 320x240 (4:3) Color
|
ROBOT_24_COLOR, // 320x240 (4:3) Color
|
||||||
ROBOT_36_COLOR, // 320x240 (4:3) Color
|
ROBOT_36_COLOR, // 320x240 (4:3) Color
|
||||||
ROBOT_72_COLOR, // 640x480 (4:3) Color
|
ROBOT_72_COLOR, // 640x480 (4:3) Color
|
||||||
CUSTOM_TEST };
|
CUSTOM_TEST
|
||||||
|
};
|
||||||
|
|
||||||
struct Color {
|
struct Color {
|
||||||
int r = -1;
|
float r = -1.0;
|
||||||
int g = -1;
|
float g = -1.0;
|
||||||
int b = -1;
|
float b = -1.0;
|
||||||
float gray_scale_value = -1;
|
float gray_scale_value = -1;
|
||||||
Color(int r, int g, int b); // 0 - 255
|
Color(float r, float g, float b); // 0 - 255
|
||||||
Color(int gray_scale_value); // 0.0 - 1.0
|
Color(int gray_scale_value); // 0.0 - 1.0, not yet implemented
|
||||||
|
Magick::ColorRGB GetMagickColor() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Pixel {
|
struct Pixel {
|
||||||
|
@ -50,23 +52,30 @@ class SstvImage {
|
||||||
void Write(); /** @todo should pass the destination path here*/
|
void Write(); /** @todo should pass the destination path here*/
|
||||||
|
|
||||||
void AddCallSign(const std::string &callsign,
|
void AddCallSign(const std::string &callsign,
|
||||||
const SstvImage::Color &color = {-2, -2, -2});
|
const SstvImage::Color &fill_color = {0.0, 1.0, 0},
|
||||||
void AddMessage(std::string message);
|
const SstvImage::Color &stroke_color = {1.0, 0, 0});
|
||||||
|
|
||||||
|
void AddText(const std::vector<std::string> &text,
|
||||||
|
const bool left_column = true,
|
||||||
|
const SstvImage::Color fill_color = {0.0, 1.0, 0.0},
|
||||||
|
const SstvImage::Color stroke_color = {1.0, 0.0, 0.0});
|
||||||
|
|
||||||
|
void AdjustColors();
|
||||||
|
|
||||||
bool GetPixel(const int x, const int y, SstvImage::Pixel &pixel);
|
bool GetPixel(const int x, const int y, SstvImage::Pixel &pixel);
|
||||||
int GetWidth() const { return width_; }
|
int GetWidth() const { return width_; }
|
||||||
int GetHeight() const { return height_; }
|
int GetHeight() const { return height_; }
|
||||||
|
|
||||||
void AdjustColors();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Scale();
|
void Scale();
|
||||||
|
|
||||||
std::pair<int, int> WorkspaceToImageCoordinates(int x, int y);
|
std::pair<int, int> WorkspaceToImageCoordinates(int x, int y);
|
||||||
|
|
||||||
int width_ = 0;
|
int width_ = 0;
|
||||||
int height_ = 0;
|
int height_ = 0;
|
||||||
double height_scaler_ = 1;
|
double height_scaler_ = 1;
|
||||||
|
const int kCallSignFontHeight_ = 25;
|
||||||
|
const int kTextFontHeight_ = 10;
|
||||||
|
|
||||||
std::string source_path_ = "";
|
std::string source_path_ = "";
|
||||||
std::string destination_path_ = "";
|
std::string destination_path_ = "";
|
||||||
|
|
|
@ -1,15 +1,24 @@
|
||||||
#include "sstv-image-tools.h"
|
#include "sstv-image-tools.h"
|
||||||
|
|
||||||
#include <Magick++/Color.h>
|
#include <Magick++/Color.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
SstvImage::Color::Color(int red, int green, int blue) {
|
SstvImage::Color::Color(float red, float green, float blue) {
|
||||||
|
if (red < 0.0 || red > 1.0 || green < 0.0 || green > 1.0 || blue < 0.0 ||
|
||||||
|
blue > 1.0) {
|
||||||
|
throw SstvImageToolsException("Invalid color value");
|
||||||
|
}
|
||||||
this->r = red;
|
this->r = red;
|
||||||
this->g = green;
|
this->g = green;
|
||||||
this->b = blue;
|
this->b = blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Magick::ColorRGB SstvImage::Color::GetMagickColor() const {
|
||||||
|
return Magick::ColorRGB(r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
SstvImage::SstvImage(SstvImage::Mode mode, std::string source_image_path,
|
SstvImage::SstvImage(SstvImage::Mode mode, std::string source_image_path,
|
||||||
std::string destination_image_path, bool crop)
|
std::string destination_image_path, bool crop)
|
||||||
: mode_(mode), crop_(crop) {
|
: mode_(mode), crop_(crop) {
|
||||||
|
@ -38,29 +47,68 @@ void SstvImage::Write() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SstvImage::AddCallSign(const std::string &callsign,
|
void SstvImage::AddCallSign(const std::string &callsign,
|
||||||
const SstvImage::Color &color) {
|
const SstvImage::Color &fill_color,
|
||||||
(void)color;
|
const SstvImage::Color &stroke_color) {
|
||||||
|
(void)fill_color;
|
||||||
|
(void)stroke_color;
|
||||||
|
|
||||||
int font_size = 25 * height_scaler_;
|
int font_size = kCallSignFontHeight_ * height_scaler_;
|
||||||
|
|
||||||
std::vector<Magick::Drawable> draw_list(
|
std::vector<Magick::Drawable> draw_list(
|
||||||
{Magick::DrawableFont("Arial-Bold"),
|
{Magick::DrawableFont("Arial-Bold"), Magick::DrawablePointSize(font_size),
|
||||||
Magick::DrawablePointSize(font_size),
|
Magick::DrawableText(0, 0 + font_size * 0.8, callsign),
|
||||||
Magick::DrawableText(0, 0 + font_size * 0.8, callsign),
|
Magick::DrawableStrokeColor(stroke_color.GetMagickColor()),
|
||||||
Magick::DrawableStrokeColor("red"),
|
Magick::DrawableStrokeWidth(2), Magick::DrawableStrokeAntialias(true),
|
||||||
Magick::DrawableStrokeWidth(2),
|
Magick::DrawableFillColor(fill_color.GetMagickColor())});
|
||||||
Magick::DrawableStrokeAntialias(true),
|
|
||||||
Magick::DrawableFillColor("green")}
|
|
||||||
);
|
|
||||||
|
|
||||||
image_.draw(draw_list);
|
image_.draw(draw_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SstvImage::AddText(const std::vector<std::string> &text,
|
||||||
|
const bool left_column,
|
||||||
|
const SstvImage::Color fill_color,
|
||||||
|
const SstvImage::Color stroke_color) {
|
||||||
|
int font_size = 10 * height_scaler_;
|
||||||
|
|
||||||
|
std::vector<Magick::Drawable> draw_list(
|
||||||
|
{Magick::DrawableFont("Arial-Bold"), Magick::DrawablePointSize(font_size),
|
||||||
|
Magick::DrawableFillColor(fill_color.GetMagickColor()),
|
||||||
|
Magick::DrawableStrokeColor(stroke_color.GetMagickColor()),
|
||||||
|
Magick::DrawableStrokeWidth(1)});
|
||||||
|
|
||||||
|
int y = left_column ? 0 : GetWidth() / 2;
|
||||||
|
|
||||||
|
int i = 1;
|
||||||
|
for (auto line : text) {
|
||||||
|
draw_list.push_back(Magick::DrawableText(
|
||||||
|
y, GetHeight() + font_size * 0.8 - (i * font_size), line));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
image_.draw(draw_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SstvImage::AdjustColors() {
|
||||||
|
image_.quantizeColorSpace(Magick::RGBColorspace);
|
||||||
|
image_.quantizeColors(256);
|
||||||
|
image_.quantize();
|
||||||
|
image_.modifyImage();
|
||||||
|
image_.gamma(1.7);
|
||||||
|
image_.enhance();
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is a hack to deal with the color space issues when reading pixel values.
|
||||||
|
Not a fan of this solution, and it needs to be fixed, but it works for now.
|
||||||
|
*/
|
||||||
|
image_.write("tmp.png");
|
||||||
|
image_.read("tmp.png");
|
||||||
|
}
|
||||||
|
|
||||||
bool SstvImage::GetPixel(const int x, const int y, SstvImage::Pixel &pixel) {
|
bool SstvImage::GetPixel(const int x, const int y, SstvImage::Pixel &pixel) {
|
||||||
if (x < 0 || x >= width_ || y < 0 || y >= height_) {
|
if (x < 0 || x >= width_ || y < 0 || y >= height_) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MagickCore::Quantum *pixels = image_.getPixels(0, 0, width_, height_);
|
MagickCore::Quantum *pixels = image_.getPixels(0, 0, width_, height_);
|
||||||
unsigned index = (y * width_ + x) * image_.channels();
|
unsigned index = (y * width_ + x) * image_.channels();
|
||||||
|
|
||||||
|
@ -70,20 +118,6 @@ bool SstvImage::GetPixel(const int x, const int y, SstvImage::Pixel &pixel) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SstvImage::AdjustColors() {
|
|
||||||
/*
|
|
||||||
This is a hack to deal with the color space issues. Not a fan of this solution.
|
|
||||||
*/
|
|
||||||
image_.quantizeColorSpace(Magick::RGBColorspace);
|
|
||||||
image_.quantizeColors(256);
|
|
||||||
image_.quantize();
|
|
||||||
image_.modifyImage();
|
|
||||||
image_.gamma(1.7);
|
|
||||||
image_.enhance();
|
|
||||||
image_.write("tmp.png");
|
|
||||||
image_.read("tmp.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
void SstvImage::Scale() {
|
void SstvImage::Scale() {
|
||||||
width_ = 0;
|
width_ = 0;
|
||||||
height_ = 0;
|
height_ = 0;
|
||||||
|
@ -123,42 +157,4 @@ void SstvImage::Scale() {
|
||||||
crop_size.aspect(true);
|
crop_size.aspect(true);
|
||||||
image_.resize(crop_size);
|
image_.resize(crop_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
//image_.enhance();
|
|
||||||
/*
|
|
||||||
image_.quantizeColorSpace(Magick::RGBColorspace);
|
|
||||||
image_.quantizeColors(256);
|
|
||||||
image_.quantize();
|
|
||||||
image_.modifyImage();
|
|
||||||
image_.colorSpace(Magick::sRGBColorspace);
|
|
||||||
image_.type(Magick::TrueColorType);
|
|
||||||
if (image_.colorSpace() == Magick::sRGBColorspace){
|
|
||||||
std::cout << "sRGBColorspace" << std::endl;
|
|
||||||
} else if (image_.colorSpace() == Magick::RGBColorspace) {
|
|
||||||
std::cout << "RGBColorspace" << std::endl;
|
|
||||||
} else if (image_.colorSpace() == Magick::CMYColorspace) {
|
|
||||||
std::cout << "CMYColorspace" << std::endl;
|
|
||||||
} else if (image_.colorSpace() == Magick::GRAYColorspace) {
|
|
||||||
std::cout << "GRAYColorspace" << std::endl;
|
|
||||||
} else {
|
|
||||||
std::cout << "Unknown colorspace" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "Channels: " << image_.channels() << std::endl;
|
|
||||||
image_.channel(Magick::RedChannel);
|
|
||||||
*/
|
|
||||||
|
|
||||||
//image_.quantizeColorSpace(Magick::RGBColorspace); // THESE
|
|
||||||
//image_.quantizeColors(256); // THESE
|
|
||||||
//image_.quantize(); // THESE
|
|
||||||
//image_.normalize();
|
|
||||||
//image_.enhance(); Made things a lot worse
|
|
||||||
|
|
||||||
/*
|
|
||||||
Known working solution:
|
|
||||||
image_.quantizeColorSpace(Magick::RGBColorspace);
|
|
||||||
image_.quantizeColors(256);
|
|
||||||
image_.quantize();
|
|
||||||
image_.modifyImage();
|
|
||||||
*/
|
|
||||||
}
|
}
|
Ładowanie…
Reference in New Issue