-
Notifications
You must be signed in to change notification settings - Fork 1
Home
Since uint8_t
is a very useful type for image processing (or anything dealing with binary data) the library typedefs uint8_t
to byte
which is quicker to type and looks tidier.
The Image
class supports a number of types (the default being byte) along with a set of depths such as 8-bit greyscale and 24-bit RGB. It provides raw access to the pixel data as a contiguous block which makes it simpler to implement image processing algorithms based around it.
#include <emergent/image/Image.hpp>
using namespace emergent;
int main(int argc, char *argv[])
{
// Standard greyscale byte image
Image<byte> grey;
// Colour byte image (24-bit, RGB)
Image<byte, rgb> colour;
// Greyscale floating-point image
Image<double> floating;
// Load from file (utilises the [freeimage](http://freeimage.sourceforge.net) library)
if (grey.Load("test.png"))
{
// Implicitly cast to byte* to give raw access to the underlying data
byte *g = grey;
const size_t size = grey.Size();
// Simple inversion of pixel values
for (size_t i=0; i<size; i++, g++)
{
*g = 255 - *g;
}
// Assign the greyscale image to the colour one, the data will be copied
// such that each channel (RGB) contains the same values.
colour = grey;
}
}
Threading helper capable of acting as a manual and auto reset event.
Basic wrapper around a time_t representing a UTC timestamp. Contains methods for converting to/from ISO 8601 and for incrementing/decrementing the timestamp.
#include <emergent/DateTime.hpp>
using namespace emergent;
int main(int argc, char *argv[])
{
auto time = DateTime::Now().AddDays(4).AddSeconds(21);
cout << time.FormatISO() << endl;
}
The class logger
is a singleton that can be initialised with multiple sinks for directing log output.
#include <emergent/logger/Logger.hpp>
using namespace emergent;
int main(int argc, char *argv[])
{
// Logs to std::cout
Log::Initialise({ make_unique<logger::Console>() });
...
// Simple logging macro
Log::Error("Something happened here");
// Formatted logging
Log::Error("There was an error: %s", errorString);
}
The Maths class contains a few static helper functions:
-
clamp
for clamping values of one type within the numeric limits of another. -
nrand
for generating a normalised pseudo-random number (0.0 to 1.0). -
cosine
andsine
lookup functions for positive integer angles in degrees.
A wrapper for STL containers that will switch the begin/end for rbegin/rend so that they can be used in a range-based for loop.
#include <emergent/Reverse.hpp>
using namespace emergent;
int main(int argc, char *argv[])
{
vector<string> values = { "a", "b", "c" };
for (auto &s : reverse(values))
{
// Will print out "c" first
cout << s << endl;
}
}
A wrapper for std::map<>
to allow range-based iteration over the keys.
#include <emergent/KeyIterator.hpp>
using namespace emergent;
int main(int argc, char *argv[])
{
map<int, string> values = { { 0, "a" }, { 2, "b" }, { 4, "c" }};
for (auto &k : key_iterator(values))
{
cout << k << endl;
}
}
The String class is simply a container for some static helper functions:
-
demangle
will demangle a function name (gcc only). -
load
will load an entire file into a std::string. -
save
will save a std::string to a file (overwriting a file if it already exists). -
explode
will split a string at the specified delimiters and return astd::vector<std::string>
. -
lowercase
will transform a string to lowercase. -
hyphenate
will return a lowercase hyphenated string from a camel-cased one (for example, given "HelloWorld" it would return "hello-world"). -
trim
will trim a specified character from both ends of a string. -
format
acts as a wrapper aroundsnprintf
.
A system for registering types and allowing new instances to be constructed by string name.
#include <emergent/Type.hpp>
using namespace emergent;
class Base {};
class Derived : public Base {};
REGISTER_TYPE(Base, Derived)
int main(int argc, char *argv[])
{
unique_ptr<Base> instance = Type<Base>::Create("Derived");
}
Creates a UUID using the std::mersenne_twister_engine to generate random numbers.
#include <emergent/Uuid.hpp>
using namespace emergent;
int main(int argc, char *argv[])
{
uuid id;
// Convert to its canonical form (xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx)
// where 'y' is one of 8, 9, a or b
cout << id.to_string() << endl;
// Alternatively convert to a std::vector<byte>
for (auto &b : id.to_binary())
{
...
}
}
A simple, lightweight profiler that uses a concurrent queue to store readings in a lock-free and yet thread-safe manner. This means that the profiler itself should provide very little overhead and therefore could be left enabled in production. The Aggregator generates and stores the statistics at regular, configurable intervals. The storage class can be extended so that results can be written wherever you wish.
Please note that the built-in storage classes have an additional dependency on libentity which is used for serialisation of aggregated statistics.
#include <emergent/profile/Profile.hpp>
using namespace emergent::profile;
int main(int argc, char *argv[])
{
// Initialise the profile aggregator with a unique ID for this process and the type of
// storage required. Time between aggregations will be 1000ms in this example.
if (!Aggregator::Instance().Initialise("my-process", make_unique<ConsoleStorage>(), 1000))
{
cout << "Problem initialising aggregator" << endl;
return -1;
}
const int THREADS = 50;
thread t[THREADS];
for (int i=0; i<THREADS; i++)
{
t[i] = thread([](){
for (int i=0; i<500; i++)
{
// Profile the sample codeblock called from many threads. When the instance
// goes out of scope the time between construction and destruction is logged.
Profile p = { "my-codeblock" };
this_thread::sleep_for(milliseconds(10));
}
});
}
for (int i=0; i<THREADS; i++) t[i].join();
return 0;
}
A simple class that provides a fixed size thread pool which, unlike std::async, does not block when the returned future is destroyed.
#include <emergent/thread/Pool.hpp>
using namespace emergent;
int main(int argc, char *argv[])
{
// A pool of 4 threads
ThreadPool<4> pool;
// Run a lambda with no return value.
auto a = pool.Run([]() {
this_thread::sleep_for(100ms);
cout << "a," << flush;
});
// Run a lambda with an integer return value.
auto b = pool.Run([]() {
this_thread::sleep_for(50ms);
cout << "b," << flush;
return 42;
});
// You do not need to do anything with the returned future.
pool.Run([]() {
cout << "c," << flush;
});
// Wait for and retrieve the integer returned from "b".
cout << b.get() << "," << flush;
// Wait for "a" to complete.
a.wait();
// After this it should have printed "c,b,42,a,done"
cout << "done" << endl;
return 0;
}