optimization: streamline image loading and remove pixel vector

- Read file once and decode from memory using stbi_load_from_memory
- Add guard for files smaller than 8 bytes
- Remove std::vector<Pixel> and accumulate histogram in downsample loop
This commit is contained in:
2026-08-08 04:37:38 +03:00
parent ecce4c8170
commit 93f5cd0ba4
+43 -42
View File
@@ -7,6 +7,7 @@
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
#include <algorithm> #include <algorithm>
#include <iterator>
#include <cstdio> #include <cstdio>
using std::cout; using std::cout;
@@ -15,10 +16,6 @@ namespace fs = std::filesystem;
bool is_jpeg(const unsigned char* buf); bool is_jpeg(const unsigned char* buf);
bool is_png(const unsigned char* buf); bool is_png(const unsigned char* buf);
struct Pixel {
unsigned char r, g, b;
};
struct Bucket { struct Bucket {
long r = 0; long r = 0;
long g = 0; long g = 0;
@@ -62,22 +59,30 @@ int main(int argc, char *argv[]) {
return 1; return 1;
} }
unsigned char header[8]; // Read the file once; detect the format from the buffer and decode from
file.read(reinterpret_cast<char*>(header), 8); // memory so the image is never read from disk a second time.
std::vector<unsigned char> buffer((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
if (buffer.size() < 8) {
cout << "File is too small to be a valid image!\n";
return 1;
}
const unsigned char* header = buffer.data();
if (is_png(header)) { if (is_png(header)) {
cout << "PNG file detected!\n"; cout << "PNG file detected!\n";
} else if (is_jpeg(header)) { } else if (is_jpeg(header)) {
cout << "JPEG file detected!\n"; cout << "JPEG file detected!\n";
} else { } else {
cout << "Unkown image file format!\n"; cout << "Unknown image file format!\n";
return 1; return 1;
} }
int width, height, channels; int width, height, channels;
unsigned char* data = stbi_load( unsigned char* data = stbi_load_from_memory(
argv[1], buffer.data(),
static_cast<int>(buffer.size()),
&width, &width,
&height, &height,
&channels, &channels,
@@ -97,46 +102,42 @@ int main(int argc, char *argv[]) {
cout << "Channels: " << channels << "\n"; cout << "Channels: " << channels << "\n";
cout << "**********\n"; cout << "**********\n";
std::vector<Pixel> samples; std::unordered_map<int, Bucket> hist;
int step = 10; //downsample rate int step = 10; //downsample rate
for (int y = 0; y< height; y += step) { long sampled = 0;
for (int x = 0; x < width; x+= step) { for (int y = 0; y < height; y += step) {
for (int x = 0; x < width; x += step) {
int idx = (y * width + x) * 3; int idx = (y * width + x) * 3;
Pixel p; unsigned char r = data[idx];
p.r = data[idx]; unsigned char g = data[idx + 1];
p.g = data[idx + 1]; unsigned char b = data[idx + 2];
p.b = data[idx + 2]; sampled++;
samples.push_back(p);
int brightness = r + g + b;
if (brightness < 60) continue; //filtering out dark pixels
int minc = std::min({r, g, b});
int maxc = std::max({r, g, b});
if (maxc - minc < 10) continue; //filtering out low saturation
//(gray) colors
int rq = r / 16;
int gq = g / 16;
int bq = b / 16;
int key = (rq << 8) | (gq << 4) | bq;
auto& bucket = hist[key];
bucket.r += r;
bucket.g += g;
bucket.b += b;
bucket.count++;
} }
} }
cout << "Sampled pixels: " << samples.size() << "\n"; cout << "Sampled pixels: " << sampled << "\n";
std::unordered_map<int, Bucket> hist;
for (auto& p : samples) {
int brightness = p.r + p.g + p.b;
if (brightness < 60) continue; //filtering out dark pixels
int minc = std::min({p.r, p.g, p.b});
int maxc = std::max({p.r, p.g, p.b});
if (maxc - minc < 10) continue; //filtering out low saturation
//(gray) colors
int rq = p.r / 16;
int gq = p.g / 16;
int bq = p.b / 16;
int key = (rq << 8) | (gq << 4) | bq;
auto& bucket = hist[key];
bucket.r += p.r;
bucket.g += p.g;
bucket.b += p.b;
bucket.count ++;
}
std::vector<Bucket> buckets; std::vector<Bucket> buckets;