This adds the first draft of DXF functionality to the filmout_display application
This commit is contained in:
parent
d5b2b63681
commit
e293c3168d
|
@ -0,0 +1,80 @@
|
||||||
|
#include <opencv2/opencv.hpp>
|
||||||
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using namespace cv;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
struct DXFHeader {
|
||||||
|
int32_t width;
|
||||||
|
int32_t height;
|
||||||
|
uint8_t bitDepth;
|
||||||
|
uint8_t version;
|
||||||
|
uint8_t flags;
|
||||||
|
uint8_t reserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DXF {
|
||||||
|
public:
|
||||||
|
explicit DXF(const string& filepath) :
|
||||||
|
_filepath(filepath),
|
||||||
|
_width(0),
|
||||||
|
_height(0),
|
||||||
|
_bitDepth(0) {
|
||||||
|
analyzeFile();
|
||||||
|
loadImageData();
|
||||||
|
}
|
||||||
|
|
||||||
|
int getWidth() const { return _width; }
|
||||||
|
int getHeight() const { return _height; }
|
||||||
|
int getBitDepth() const { return _bitDepth; }
|
||||||
|
bool hasDXFHeader() const { return true; }
|
||||||
|
|
||||||
|
Mat to8bitBGR() const;
|
||||||
|
Mat to10bitBGR() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
string _filepath;
|
||||||
|
int _width;
|
||||||
|
int _height;
|
||||||
|
int _bitDepth;
|
||||||
|
Mat _imageData;
|
||||||
|
|
||||||
|
void analyzeFile();
|
||||||
|
bool readDXFHeader(ifstream& file);
|
||||||
|
void analyzeDXFContent(ifstream& file);
|
||||||
|
int detectBitDepth(const vector<uint8_t>& sample);
|
||||||
|
void loadImageData();
|
||||||
|
void unpackBits(const std::vector<uint8_t>& rawData);
|
||||||
|
void calculateDimensions(streamsize fileSize);
|
||||||
|
void validateImageProperties();
|
||||||
|
|
||||||
|
static uint16_t extractBits(const std::vector<uint8_t>& buffer, size_t bitPos, int bitDepth, uint16_t maxValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Example usage
|
||||||
|
int main() {
|
||||||
|
try {
|
||||||
|
DXF dxf("sample.dxf");
|
||||||
|
|
||||||
|
cout << "Image dimensions: " << dxf.getWidth() << "x" <<
|
||||||
|
dxf.getHeight() << endl;
|
||||||
|
cout << "Original bit depth: " << dxf.getBitDepth() << endl;
|
||||||
|
|
||||||
|
Mat bgr8bit = dxf.to8BitBGR();
|
||||||
|
Mat bgr10bit = dxf.to10BitBGR();
|
||||||
|
|
||||||
|
|
||||||
|
imwrite("output_8bit_bgr.png", bgr8bit);
|
||||||
|
imwrite("output_10bit_bgr.png", bgr10bit);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (const exception& e) {
|
||||||
|
cerr << "Error: " << e.what() << endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}*/
|
|
@ -17,6 +17,8 @@
|
||||||
#include <opencv2/highgui.hpp>
|
#include <opencv2/highgui.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "dxf.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace cv;
|
using namespace cv;
|
||||||
|
|
||||||
|
@ -28,6 +30,8 @@ class Image {
|
||||||
Mat loaded;
|
Mat loaded;
|
||||||
Mat resized;
|
Mat resized;
|
||||||
Mat image;
|
Mat image;
|
||||||
|
string getExtLower(const string& path);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Image();
|
Image();
|
||||||
void setDimensions(uint16_t w, uint16_t h) { width = w; height = h; };
|
void setDimensions(uint16_t w, uint16_t h) { width = w; height = h; };
|
||||||
|
|
|
@ -0,0 +1,186 @@
|
||||||
|
#include "dxf.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
Mat DXF::to8bitBGR() const {
|
||||||
|
if (_imageData.empty()) {
|
||||||
|
throw runtime_error("No image data loaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat output(_height, _width, CV_8UC3);
|
||||||
|
|
||||||
|
double scale = 255.0 / ((1 << _bitDepth) - 1);
|
||||||
|
|
||||||
|
for (int y = 0; y < _height; ++y) {
|
||||||
|
const uint16_t* srcRow = _imageData.ptr<uint16_t>(y);
|
||||||
|
uint8_t* dstRow = output.ptr<uint8_t>(y);
|
||||||
|
|
||||||
|
for (int x = 0; x < _width; ++x) {
|
||||||
|
uint8_t value = static_cast<uint8_t>(srcRow[x] * scale + 0.5);
|
||||||
|
dstRow[x * 3] = value; // B
|
||||||
|
dstRow[x * 3 + 1] = value; // G
|
||||||
|
dstRow[x * 3 + 2] = value; // R
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat DXF::to10bitBGR() const {
|
||||||
|
if (_imageData.empty()) {
|
||||||
|
throw runtime_error("No image data loaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat output(_height, _width, CV_16UC3);
|
||||||
|
|
||||||
|
double scale = 1023.0 / ((1 << _bitDepth) - 1);
|
||||||
|
|
||||||
|
for (int y = 0; y < _height; ++y) {
|
||||||
|
const uint16_t* srcRow = _imageData.ptr<uint16_t>(y);
|
||||||
|
uint16_t* dstRow = output.ptr<uint16_t>(y);
|
||||||
|
|
||||||
|
for (int x = 0; x < _width; ++x) {
|
||||||
|
uint16_t value = static_cast<uint16_t>(srcRow[x] * scale + 0.5);
|
||||||
|
value = min(value, static_cast<uint16_t>(1023));
|
||||||
|
|
||||||
|
uint16_t shiftedValue = value << 6;
|
||||||
|
|
||||||
|
dstRow[x * 3] = shiftedValue; // B
|
||||||
|
dstRow[x * 3 + 1] = shiftedValue; // G
|
||||||
|
dstRow[x * 3 + 2] = shiftedValue; // R
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DXF::analyzeFile() {
|
||||||
|
ifstream file(_filepath, ios::binary);
|
||||||
|
if (!file.is_open()) {
|
||||||
|
throw runtime_error("Could not open file: " + _filepath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!readDXFHeader(file)) {
|
||||||
|
analyzeDXFContent(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
validateImageProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DXF::readDXFHeader(ifstream& file) {
|
||||||
|
struct DXFHeader {
|
||||||
|
uint32_t magic;
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
uint8_t bitDepth;
|
||||||
|
uint8_t version;
|
||||||
|
uint16_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
DXFHeader header;
|
||||||
|
file.read(reinterpret_cast<char*>(&header), sizeof(header));
|
||||||
|
|
||||||
|
if (file.gcount() != sizeof(header)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.magic != 0x44584631) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_width = header.width;
|
||||||
|
_height = header.height;
|
||||||
|
_bitDepth = header.bitDepth;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DXF::analyzeDXFContent(ifstream& file) {
|
||||||
|
file.seekg(0, ios::end);
|
||||||
|
streamsize fileSize = file.tellg();
|
||||||
|
file.seekg(0, ios::beg);
|
||||||
|
|
||||||
|
vector<uint8_t> sample(min(static_cast<streamsize>(1024), fileSize));
|
||||||
|
file.read(reinterpret_cast<char*>(sample.data()), sample.size());
|
||||||
|
|
||||||
|
_bitDepth = detectBitDepth(sample);
|
||||||
|
|
||||||
|
calculateDimensions(fileSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DXF::detectBitDepth(const vector<uint8_t>& sample) {
|
||||||
|
uint16_t maxValue = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < sample.size() - 1; i += 2) {
|
||||||
|
uint16_t value = (static_cast<uint16_t>(sample[i + 1]) << 8) | sample[i];
|
||||||
|
maxValue = max(maxValue, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bitDepth = 16;
|
||||||
|
while (bitDepth > 8 && maxValue < (1 << (bitDepth - 1))) {
|
||||||
|
bitDepth--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bitDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DXF::loadImageData() {
|
||||||
|
ifstream file(_filepath, ios::binary);
|
||||||
|
if (!file.is_open()) {
|
||||||
|
throw runtime_error("Could not open file: " + _filepath);
|
||||||
|
}
|
||||||
|
if (hasDXFHeader()) {
|
||||||
|
file.seekg(sizeof(struct DXFHeader));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t dataSize = static_cast<size_t>(ceil(_width * _height * _bitDepth / 8.0));
|
||||||
|
vector<uint8_t> rawData(dataSize);
|
||||||
|
|
||||||
|
file.read(reinterpret_cast<char*>(rawData.data()), dataSize);
|
||||||
|
|
||||||
|
_imageData = Mat(_height, _width, CV_16UC1);
|
||||||
|
|
||||||
|
unpackBits(rawData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DXF::unpackBits(const vector<uint8_t>& rawData) {
|
||||||
|
size_t bitPos = 0;
|
||||||
|
const uint16_t maxValue = (1 << _bitDepth) - 1;
|
||||||
|
|
||||||
|
for (int y = 0; y < _height; ++y) {
|
||||||
|
uint16_t* row = _imageData.ptr<uint16_t>(y);
|
||||||
|
for (int x = 0; x < _width; ++x) {
|
||||||
|
row[x] = extractBits(rawData, bitPos, _bitDepth, maxValue);
|
||||||
|
bitPos += _bitDepth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t DXF::extractBits(const vector<uint8_t>& buffer, size_t bitPos, int bitDepth, uint16_t maxValue) {
|
||||||
|
size_t bytePos = bitPos / 8;
|
||||||
|
size_t bitOffset = bitPos % 8;
|
||||||
|
|
||||||
|
uint32_t temp = 0;
|
||||||
|
for (int i = 0; i < 3 && bytePos + i < buffer.size(); ++i) {
|
||||||
|
temp |= static_cast<uint32_t>(buffer[bytePos + i]) << (16 - (i * 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
temp >>= (24 - (bitOffset + bitDepth));
|
||||||
|
return static_cast<uint16_t>(temp & maxValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DXF::calculateDimensions(streamsize fileSize) {
|
||||||
|
int pixelCount = (fileSize * 8) / _bitDepth;
|
||||||
|
_width = static_cast<int>(sqrt(pixelCount));
|
||||||
|
_height = _width;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DXF::validateImageProperties() {
|
||||||
|
if (_width <= 0 || _height <= 0 ||
|
||||||
|
_width > 65536 || _height > 65536) {
|
||||||
|
throw runtime_error("Invalid image dimensions");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_bitDepth < 8 || _bitDepth > 16) {
|
||||||
|
throw runtime_error("Unsupported bit depth: " + to_string(_bitDepth));
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,12 @@ Mat Image::getBlank () {
|
||||||
|
|
||||||
Mat Image::loadImage (string& image_path, uint64_t& x, uint64_t& y, uint64_t& w, uint64_t& h) {
|
Mat Image::loadImage (string& image_path, uint64_t& x, uint64_t& y, uint64_t& w, uint64_t& h) {
|
||||||
string located_path = samples::findFile(image_path);
|
string located_path = samples::findFile(image_path);
|
||||||
loaded = imread(located_path, IMREAD_COLOR);
|
if (getExtLower(located_path) == ".dxf") {
|
||||||
|
DXF dxf(located_path);
|
||||||
|
loaded = dxf.to8bitBGR();
|
||||||
|
} else {
|
||||||
|
loaded = imread(located_path, IMREAD_COLOR);
|
||||||
|
}
|
||||||
image = getBlank();
|
image = getBlank();
|
||||||
|
|
||||||
if (loaded.empty()) {
|
if (loaded.empty()) {
|
||||||
|
@ -38,3 +43,13 @@ Mat Image::loadImage (string& image_path, uint64_t& x, uint64_t& y, uint64_t& w,
|
||||||
}
|
}
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string Image::getExtLower (const string& path) {
|
||||||
|
size_t pos = path.find_last_of('.');
|
||||||
|
if (pos != string::npos) {
|
||||||
|
string ext = path.substr(pos + 1);
|
||||||
|
transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
|
||||||
|
return ext;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
|
@ -214,7 +214,7 @@ void display () {
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
glutSwapBuffers();
|
glutSwapBuffers();
|
||||||
|
|
||||||
//glFlush();
|
//glFlush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void timer(int value) {
|
void timer(int value) {
|
||||||
|
|
Loading…
Reference in New Issue