libsdfio 1.0.0
Reader and writer for ISO 25178-71 SDF surface data files in C
Loading...
Searching...
No Matches
opencv.cpp
// Smooth an SDF file with OpenCV.
#include <sdfio/file.h>
#include <sdfio/sdfio.h>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <cstddef>
#include <iostream>
#include <limits>
#include <memory>
#include <stdexcept>
#include <string>
namespace
{
using Reader = std::unique_ptr<sdfio_reader, decltype(&sdfio_reader_free)>;
using Writer = std::unique_ptr<sdfio_writer, decltype(&sdfio_writer_free)>;
using Header = std::unique_ptr<sdfio_header, decltype(&sdfio_header_free)>;
void check(sdfio_status status, const char *message)
{
if (status != SDFIO_OK)
{
throw std::runtime_error(std::string(sdfio_status_string(status)) + ": "
+ message);
}
}
Header copy_header(const sdfio_header *source)
{
sdfio_header *header = nullptr;
sdfio_header_copy(header, source);
return {header, sdfio_header_free};
}
Reader create_reader()
{
sdfio_reader *reader = nullptr;
return {reader, sdfio_reader_free};
}
Writer create_writer()
{
sdfio_writer *writer = nullptr;
return {writer, sdfio_writer_free};
}
Reader open(const char *path)
{
Reader reader = create_reader();
check(sdfio_open_file(reader.get(), path),
return reader;
}
// An image counts its rows from the top and a surface from y = 0. The layout
// has a negative row stride and the pointer given with it is at the last row,
// so the first row of the file is the last row in memory and no copy is
// created. The step of the image is the row stride, so that an image that is
// not continuous, such as a region of interest, is used as it is.
sdfio_layout bottom_up(const cv::Mat &image)
{
layout.row_stride = -static_cast<ptrdiff_t>(image.step);
return layout;
}
cv::Mat read_heights(sdfio_reader *reader)
{
const sdfio_header *header = sdfio_reader_header(reader);
cv::Mat heights(static_cast<int>(sdfio_header_rows(header)),
static_cast<int>(sdfio_header_columns(header)), CV_32F);
const sdfio_layout layout = bottom_up(heights);
check(sdfio_read_heights(reader, &layout, heights.ptr(heights.rows - 1)),
return heights;
}
// Only the points that are measured enter the average: the blur of the heights
// is divided by the blur of the mask of these points. A point that is not
// measured stays NaN.
cv::Mat smooth(const cv::Mat &heights)
{
cv::Mat measured;
cv::compare(heights, heights, measured, cv::CMP_EQ);
cv::Mat weights;
measured.convertTo(weights, CV_32F, 1.0 / 255.0);
cv::Mat values = heights.clone();
values.setTo(0.0, ~measured);
cv::GaussianBlur(values, values, cv::Size(5, 5), 1.0);
cv::GaussianBlur(weights, weights, cv::Size(5, 5), 1.0);
cv::Mat smoothed;
cv::divide(values, weights, smoothed);
smoothed.setTo(std::numeric_limits<float>::quiet_NaN(), ~measured);
return smoothed;
}
void write_heights(const char *path, const sdfio_header *source,
const cv::Mat &heights)
{
Header header = copy_header(source);
Writer writer = create_writer();
check(sdfio_create_file(writer.get(), path, header.get()),
const sdfio_layout layout = bottom_up(heights);
check(sdfio_write_heights(writer.get(), &layout,
heights.ptr(heights.rows - 1)),
check(sdfio_end_file(writer.get()),
}
cv::Mat read_into_region(const char *path)
{
const Reader reader = open(path);
const sdfio_header *header = sdfio_reader_header(reader.get());
cv::Mat canvas = cv::Mat::zeros(200, 300, CV_32F);
cv::Mat region =
canvas(cv::Rect(100, 50, static_cast<int>(sdfio_header_columns(header)),
static_cast<int>(sdfio_header_rows(header))));
const sdfio_layout layout = bottom_up(region);
check(
sdfio_read_heights(reader.get(), &layout, region.ptr(region.rows - 1)),
return canvas;
}
} // namespace
int main(int argc, char **argv)
{
if (argc < 3)
{
std::cerr << "usage: " << argv[0] << " input.sdf output.sdf\n";
return 1;
}
const char *input = argv[1];
const char *output = argv[2];
try
{
const Reader reader = open(input);
const cv::Mat smoothed = smooth(read_heights(reader.get()));
write_heights(output, sdfio_reader_header(reader.get()), smoothed);
read_into_region(input);
}
catch (const std::exception &error)
{
std::cerr << error.what() << "\n";
return 1;
}
}
Files by path, and the stream over a C file.
sdfio_status sdfio_open_file(sdfio_reader *reader, const char *path)
Opens the file at a path as the source and reads its header, as sdfio_open_stream() does for a stream...
sdfio_status sdfio_create_file(sdfio_writer *writer, const char *path, const sdfio_header *header)
Creates the file at a path and starts it as sdfio_create_stream() does.
struct sdfio_header sdfio_header
Header of a file, with the field names of the standard.
Definition header.h:42
void sdfio_header_free(sdfio_header *header)
Releases a header that sdfio_header_create() created.
uint32_t sdfio_header_rows(const sdfio_header *header)
Returns the number of rows N of the data matrix: 1 for a profile.
sdfio_status sdfio_header_create(const sdfio_allocator *allocator, sdfio_header **header)
Creates a header with default values.
sdfio_status sdfio_header_copy(sdfio_header *dst, const sdfio_header *src)
Copies every field of a header into another header, which keeps its allocator.
uint32_t sdfio_header_columns(const sdfio_header *header)
Returns the number of columns M of the data matrix: the points along x.
sdfio_status sdfio_header_set_format(sdfio_header *header, sdfio_format format)
Sets the format of the file.
sdfio_status sdfio_header_set_data_type(sdfio_header *header, sdfio_data_type data_type)
Sets the data type of the coded values in the data area.
const sdfio_layout * sdfio_layout_packed(sdfio_data_type type)
Returns the layout of a plain array: the elements follow each other and the rows follow each other.
sdfio_status sdfio_reader_add_binary(sdfio_reader *reader)
Adds the binary format to the formats that the reader reads, the version numbers bISO-1....
const sdfio_header * sdfio_reader_header(const sdfio_reader *reader)
Returns the header of the opened file, or null if no file is open.
struct sdfio_reader sdfio_reader
Opaque handle of a reader.
Definition reader.h:58
sdfio_status sdfio_reader_add_ascii(sdfio_reader *reader)
Adds the ASCII format to the formats that the reader reads, the version numbers aISO-1....
sdfio_status sdfio_reader_create(const sdfio_allocator *allocator, sdfio_reader **reader)
Creates a reader.
sdfio_status sdfio_read_heights(sdfio_reader *reader, const sdfio_layout *layout, void *dst)
Reads the remaining rows as heights in metres into a buffer that lies in memory as the layout describ...
const char * sdfio_reader_error_message(const sdfio_reader *reader)
Returns a description of the most recent failure of the reader, or an empty string if none occurred.
void sdfio_reader_free(sdfio_reader *reader)
Releases a reader and closes the file that sdfio_open_file() opened, if any.
Reading and writing of ISO 25178-71 SDF surface data files.
Description of a buffer of the caller for heights or for the values of the data area: the type of its...
Definition layout.h:45
ptrdiff_t row_stride
Distance in bytes between consecutive rows.
Definition layout.h:62
const char * sdfio_status_string(sdfio_status status)
Returns a constant description of a status.
@ SDFIO_BINARY
Binary format.
Definition types.h:83
sdfio_status
Result of a function call.
Definition types.h:31
@ SDFIO_OK
The call succeeded.
Definition types.h:33
const sdfio_allocator * sdfio_default_allocator(void)
Returns the allocator that uses malloc() and free().
@ SDFIO_TYPE_FLOAT
float: IEEE 754 binary32.
Definition types.h:114
sdfio_status sdfio_writer_add_binary(sdfio_writer *writer)
Adds the binary format to the formats that the writer writes.
sdfio_status sdfio_writer_create(const sdfio_allocator *allocator, sdfio_writer **writer)
Creates a writer.
struct sdfio_writer sdfio_writer
Opaque handle of a writer.
Definition writer.h:69
const char * sdfio_writer_error_message(const sdfio_writer *writer)
Returns a description of the most recent failure of the writer, or an empty string if none occurred.
void sdfio_writer_free(sdfio_writer *writer)
Releases a writer.
sdfio_status sdfio_write_heights(sdfio_writer *writer, const sdfio_layout *layout, const void *src)
Writes the whole data area from a matrix of heights in metres that lies in memory as the layout descr...
sdfio_status sdfio_end_file(sdfio_writer *writer)
Ends the file: closes the trailer, the last record, flushes the stream and, for a file that sdfio_cre...