[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Reply to: [list | sender only]
Re: [Imgcif-l] High speed image compression
- To: The Crystallographic Binary File and its imgCIF application to image data <[email protected]>
- Subject: Re: [Imgcif-l] High speed image compression
- From: Justin Anderson <[email protected]>
- Date: Fri, 29 Jul 2011 11:32:06 -0500
- In-Reply-To: <[email protected]>
- Organization: Rayonix, LLC
- References: <[email protected]><CAMkkSyn+uC4VxZpaqAhQb=ENzJYEgj+N5CCs+bPt2-JS+S_otQ@mail.gmail.com><[email protected]> <[email protected]><a06240801ca58404ba1d6@[192.168.2.101]><a06240802ca5875ce2c7f@[192.168.2.101]><[email protected]>
By the way, attached is the new code. On 7/29/11 10:41 AM, Justin Anderson wrote: > Thank you everyone for the great suggestions. > > Note: I am not including the time to write the compressed data to disk > intentionally. I want to test only the compression time and not the > disk speed. We will be writing these files to a PCIe solid state > drive in production. These drives can write uncompressed frames in > real time. > > Our goal is to be decently under 100 ms with the 4K (actually 1920 x > 1920), 2 byte images to keep up at 10 fps. > > On an Intel Core i7 940 processor the same code runs in 50 - 60 ms. > > Some new runtimes (on the Core i7): > Reserving the vector space for the compressed data ahead of time: > 40 - 50 ms > Adding compressed data via address instead of push_back: > 30 - 40 ms > > Hopefully with the image correction time and transfer times this will > work. > > ~Justin > > On 7/29/11 9:40 AM, Herbert J. Bernstein wrote: >> And you can gain a little more speed once you preallocate by >> switching internally from indexed references to Vectors to >> indexed references to C pointers to the same Vectors, >> e.g. >> >> const int16_t * vptr; >> char * pptr; >> vptr =&values[0]; >> >> and, after you preallocate packed >> >> pptr =&packed[0]; >> >> >> At 6:53 AM -0400 7/29/11, Herbert J. Bernstein wrote: >>> I agree. On my Mac, the time also drops sharply with pre-allocation >>> and [] >>> instead of push_back. >>> >>> >>> At 10:51 AM +0200 7/29/11, Jonathan WRIGHT wrote: >>>> Dear Justin, >>>> >>>> Your code counts the time compressing, but not the time writing the >>>> file, which is much longer for me. As it stands, you might gain a >>>> little >>>> by adding "packed.reserve(size*2)" just before the call to compress >>>> (54 >>>> to 38 ms here on vista64, 3.3 Ghz). That falls further (28 ms) if you >>>> stop using "push_back" and instead allocate something which is >>>> "certainly" large enough to start with and use packed[p++]=c. >>>> >>>> Cheers, >>>> >>>> Jon >>>> >>>> On 29/07/2011 00:36, Justin Anderson wrote: >>>>> Thanks Nicholas. >>>>> >>>>> I only made a couple small changes to Graeme's code. 1: to load >>>>> an image >>>>> from a file and write to file and 2: to pass the data vectors by >>>>> reference. The last change seems to have sped things up a >>>>> little but >>>>> it's still taking 110 - 130 ms to compress which is too slow. >>>>> We are not >>>>> as concerned with decompression speed as that will not need to >>>>> occur in >>>>> real-time. >>>>> >>>>> I put on our FTP here: >>>>> ftp://ftp.rayonix.com/pub/del_in_30_days/byte_offset.tgz. >>>>> >>>>> Thanks, >>>>> >>>>> Justin >>>>> >>>>> On 7/28/11 2:06 PM, Nicholas Sauter wrote: >>>>>> Justin, >>>>>> >>>>>> Just some comments based on our experience...first, I haven't >>>>>> tried the >>>>>> compression extensively, just the decompression. But I've >>>>>> found Graeme's >>>>>> decompression code to be significantly faster than the CBF >>>>>> library, first >>>>>> because it is buffer-based instead of file-based, and also >>>>>> because it >>>>>> hard-codes some assumptions about data depth. >>>>>> >>>>>> I'd be happy to examine this in more detail if there is some >>>>>> way to share >>>>>> your code example... >>>>>> >>>>>> Nick >>>>>> >>>>>> On Thu, Jul 28, 2011 at 11:46 AM, Justin >>>>>> Anderson<[email protected]>wrote: >>>>>> >>>>>>> Hello all, >>>>>>> >>>>>>> I have run Graeme's byte offset code on a 4k x 4k (2 byte depth) >>>>>>> Gaussian >>>>>>> noise image and found it to compress the image in around 150 >>>>>>> ms (64-bit >>>>>>> RHEL, Pentium D 3.46GHz). Using CBF library with byte offset >>>>>>> compression, I >>>>>>> find the compression takes around 125 ms. >>>>>>> >>>>>>> This will be too slow to keep up with our high speed CCD >>>>>>> cameras. We are >>>>>>> considering parallelizing the byte offset routine by >>>>>>> operating on >>>>>>> each line >>>>>>> of the image individually. Note that this would mean that a >>>>>>> given >>>>>>> compressed image would be stored differently than via the >>>>>>> whole image >>>>>>> algorithm. >>>>>>> >>>>>>> Has anyone been thinking about this already or does anyone >>>>>>> have any >>>>>>> thoughts? >>>>>>> >>>>>>> Regards, >>>>>>> >>>>>>> Justin >>>>>>> >>>>>>> -- >>>>>>> Justin Anderson >>>>>>> Software Engineer >>>>>>> Rayonix, LLC >>>>>>> [email protected] >>>>>>> 1880 Oak Ave. #120 >>>>>>> Evanston, IL, USA 60201 >>>>>>> PH:+1.847.869.1548 >>>>>>> FX:+1.847.869.1587 >>>>>>> >>>>>>> >>>>>>> _______________________________________________ >>>>>>> imgcif-l mailing list >>>>>>> [email protected] >>>>>>> http://scripts.iucr.org/mailman/listinfo/imgcif-l >>>>>>> >>>>>>> >>>>>> >>>>> >>>>> _______________________________________________ >>>>> imgcif-l mailing list >>>>> [email protected] >>>>> http://scripts.iucr.org/mailman/listinfo/imgcif-l >>>> _______________________________________________ >>>> imgcif-l mailing list >>>> [email protected] >>>> http://scripts.iucr.org/mailman/listinfo/imgcif-l >>> >>> -- >>> ===================================================== >>> Herbert J. Bernstein, Professor of Computer Science >>> Dowling College, Kramer Science Center, KSC 121 >>> Idle Hour Blvd, Oakdale, NY, 11769 >>> >>> +1-631-244-3035 >>> [email protected] >>> ===================================================== >>> _______________________________________________ >>> imgcif-l mailing list >>> [email protected] >>> http://scripts.iucr.org/mailman/listinfo/imgcif-l >>
/*
* byte_offset.cpp
*
* An implementation of the byte_offset compression scheme used with CBF
* images with the hopeful intention of replacing existing Python code for
* doing this with something quicker. Main routines are:
*
* vector<char> compress(vector<int>)
* vector<int> uncompress(vector<char>)
*
*/
#include <iostream>
#include <fstream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <stdint.h>
using namespace std;
// unions to assist in byte manipulation
typedef union {
char b[2];
short s;
} u_s;
typedef union {
char b[4];
int i;
} u_i;
// functions for byte swapping
void byte_swap_short(char * b)
{
char c;
c = b[0];
b[0] = b[1];
b[1] = c;
return;
}
void byte_swap_int(char * b)
{
char c;
c = b[0];
b[0] = b[3];
b[3] = c;
c = b[1];
b[1] = b[2];
b[2] = c;
return;
}
// helper function: is this machine little endian? CBF files are
bool little_endian()
{
int i = 0x1;
char b = ((u_i *) &i)[0].b[0];
if (b == 0)
{
return false;
}
else
{
return true;
}
}
// main functions
vector<int16_t> read_from_file() {
int16_t read_short;
int num_read = 0;
vector<int16_t> data;
ifstream fin("comp_test_image.raw", ios::binary);
if (! fin) {
cout << "Error opening image file!" << endl;
return data;
}
while (fin.read((char *) &read_short, sizeof(read_short))) {
data.push_back(read_short);
++num_read;
}
cout << "read_from_file: read " << num_read << " pixels." << endl;
fin.close();
return data;
}
template <class T>
bool write_to_file(const vector<T> data, const string filename) {
ofstream fout(filename.c_str());
if (!fout) {
cout << "write_to_file: ERROR opening file for writing!" << endl;
return false;
}
for(typename vector<T>::const_iterator it = data.begin(); it != data.end(); ++it) {
fout.write((char *) &(*it), sizeof(*it));
}
fout.close();
return true;
}
void compress(const vector<int16_t> &values, vector<char> &packed)
{
int current = 0;
int delta, i;
unsigned int j;
//bool le = little_endian();
short s;
char c;
char * b;
int size = values.size();
for (j = 0; j < size; j++)
{
delta = values[j] - current;
if ((-127 <= delta) && (delta <= 127))
{
c = (char) delta;
packed.push_back(c);
current += delta;
continue;
}
packed.push_back(-128);
if ((-32767 <= delta) && (delta <= 32767))
{
s = (short) delta;
b = ((u_s *) & s)[0].b;
#if 0
if (!le)
{
byte_swap_short(b);
}
#endif
packed.push_back(b[0]);
packed.push_back(b[1]);
current += delta;
continue;
}
cout << "compress: Rayonix not expected to get here right now!" << endl;
s = -32768;
b = ((u_s *) & s)[0].b;
#if 0
if (!le)
{
byte_swap_short(b);
}
#endif
packed.push_back(b[0]);
packed.push_back(b[1]);
if ((-2147483647 <= delta) && (delta <= 2147483647))
{
i = delta;
b = ((u_i *) & i)[0].b;
#if 0
if (!le)
{
byte_swap_int(b);
}
#endif
packed.push_back(b[0]);
packed.push_back(b[1]);
packed.push_back(b[2]);
packed.push_back(b[3]);
current += delta;
continue;
}
/* FIXME I should not get here */
}
}
void compress_C(const int16_t *values, const int n_values, char *packed, int *n_packed)
{
int current = 0;
int delta, i;
unsigned int j;
//bool le = little_endian();
short s;
char c;
char * b;
char *packed_p;
int size = n_values;
packed_p = packed;
for (j = 0; j < size; j++)
{
delta = values[j] - current;
if ((-127 <= delta) && (delta <= 127))
{
c = (char) delta;
*packed_p++ = c;
current += delta;
continue;
}
*packed_p++ = -128;
if ((-32767 <= delta) && (delta <= 32767))
{
s = (short) delta;
b = ((u_s *) & s)[0].b;
#if 0
if (!le)
{
byte_swap_short(b);
}
#endif
*packed_p++ = b[0];
*packed_p++ = b[1];
current += delta;
continue;
}
cout << "compress: Rayonix not expected to get here right now!" << endl;
s = -32768;
b = ((u_s *) & s)[0].b;
#if 0
if (!le)
{
byte_swap_short(b);
}
#endif
*packed_p++ = b[0];
*packed_p++ = b[1];
if ((-2147483647 <= delta) && (delta <= 2147483647))
{
i = delta;
b = ((u_i *) & i)[0].b;
#if 0
if (!le)
{
byte_swap_int(b);
}
#endif
*packed_p++ = b[0];
*packed_p++ = b[1];
*packed_p++ = b[2];
*packed_p++ = b[3];
current += delta;
continue;
}
/* FIXME I should not get here */
}
*n_packed = packed_p - packed;
}
void uncompress(const vector<char> &packed, vector<int16_t> &values)
{
int16_t current = 0;
unsigned int j = 0;
short s;
uint16_t t;
char c;
int i;
//bool le = little_endian();
int size = packed.size();
while (j < size)
{
c = packed[j];
j += 1;
if (c != -128)
{
current += c;
values.push_back(current);
continue;
}
((u_s *) & s)[0].b[0] = packed[j];
((u_s *) & s)[0].b[1] = packed[j + 1];
j += 2;
#if 0
if (!le)
{
byte_swap_short((char *) &s);
}
#endif
if (s != -32768)
{
current += s;
values.push_back(current);
continue;
}
cout << "uncompress: Rayonix not expected to get here right now!" << endl;
((u_i *) & i)[0].b[0] = packed[j];
((u_i *) & i)[0].b[1] = packed[j + 1];
((u_i *) & i)[0].b[2] = packed[j + 2];
((u_i *) & i)[0].b[3] = packed[j + 3];
j += 4;
#if 0
if (!le)
{
byte_swap_int((char *) &i);
}
#endif
current += i;
values.push_back(current);
}
}
// helper for timing tests
double ms(clock_t t1, clock_t t2)
{
return 1000.0 * (t2 - t1) / CLOCKS_PER_SEC;
}
// demo / test code
int main(int argc,
char ** argv)
{
vector<int16_t> values = read_from_file();
unsigned int j;
unsigned int size = 4096 * 4096 * 2;
clock_t start;
#if 0
start = clock();
for (j = 0; j < size; j ++)
{
values.push_back((rand() & 0xffff));
}
cout << "Generating: " << ms(start, clock()) << endl;
#endif
start = clock();
#define USE_RESERVE 1
#define USE_COMPRESS_C 1
vector<char> packed;
#if USE_COMPRESS_C
int packed_size;
packed.resize(size, 0);
compress_C(values.data(), values.size(), packed.data(), &packed_size);
packed.resize(packed_size);
#else
#if USE_RESERVE
packed.reserve(size);
#endif
compress(values, packed);
#endif
cout << "Packing: " << ms(start, clock()) << endl;
write_to_file<char>(packed, "packed.raw");
start = clock();
vector<int16_t> unpacked;
uncompress(packed, unpacked);
cout << "Unpacking: " << ms(start, clock()) << endl;
write_to_file<int16_t>(unpacked, "unpacked.raw");
#if 1
cout << "Verifying unpacked data matches original data..." << endl;
for (j = 0; j < unpacked.size(); j ++)
{
if (unpacked[j] != values[j])
{
cout << "Error for index " << j << endl;
}
}
cout << "Done." << endl;
#endif
return 0;
}
_______________________________________________ imgcif-l mailing list [email protected] http://scripts.iucr.org/mailman/listinfo/imgcif-l
Reply to: [list | sender only]
- Follow-Ups:
- Re: [Imgcif-l] High speed image compression (Jonathan WRIGHT)
- References:
- [Imgcif-l] High speed image compression (Justin Anderson)
- Re: [Imgcif-l] High speed image compression (Nicholas Sauter)
- Re: [Imgcif-l] High speed image compression (Justin Anderson)
- Re: [Imgcif-l] High speed image compression (Jonathan WRIGHT)
- Re: [Imgcif-l] High speed image compression (Herbert J. Bernstein)
- Re: [Imgcif-l] High speed image compression (Herbert J. Bernstein)
- Re: [Imgcif-l] High speed image compression (Justin Anderson)
- Prev by Date: Re: [Imgcif-l] High speed image compression
- Next by Date: Re: [Imgcif-l] High speed image compression
- Prev by thread: Re: [Imgcif-l] High speed image compression
- Next by thread: Re: [Imgcif-l] High speed image compression
- Index(es):

