Skip to Main Content Skip to Search
Login
File Exchange
MATLAB Newsgroup
Link Exchange
  Blogs  
 Contest 
MathWorks.com

Thread Subject: load & display multichannel images quickly

Subject: load & display multichannel images quickly

From: jay vaughan

Date: 08 May, 2008 19:06:05

Message: 1 of 5

Hi again,

I am trying to optimize the speed of loading in three
MxN arrays and assigning them to an 8 bit MxNx3 array
(RGB) to be displayed.

It's a sensitive part of a GUI I am working on, but
I am having trouble optimizing it. A shortened version of
the code is at the bottom.

One problem is that if the floor and ceiling inputs,
(contrast/brightness parameters), are doubles then
MATLAB executes the code too slowly I presume since
it is converting the term (255/(c1-f1)) from double
to uint8. If the floor and ceiling inputs are uint8,
MATLAB executes the code more quickly but then
rounds the factor (255/(c1-f1)) before multiplying,
which reduces the bit depth of the contrast pretty
badly.

The speed is close to what I need (a factor of 2
improvement would be great), but I am not sure how
to speed things up further.

Sometimes when I find myself in this kind of pickle
it means I am going about the problem the wrong way.
For instance, is there be a better solution with
some clever way of adjusting the colormapping
rather than adjusting the data itself?

Thanks,
J

% initialize frame
frame_size = [256 256];
frame = zeros(frame_size(1),frame_size(2),3,'uint8');

% get floor & ceiling inputs (min & max in data channels)
f1 = 10; f2 = 10; f3 = 10;
c1 = 10; c2 = 10; c3 = 10;

% M maps data channels (row) to RGB weight (column)
M = [1 0 0; 0 1 0; 0 0 1];

% read in the three data channels
ch1 = (fread(fid1, frame_size, '*uint8')-f1)*(255/(c1-f1));
ch2 = (fread(fid2, frame_size, '*uint8')-f2)*(255/(c2-f2));
ch3 = (fread(fid3, frame_size, '*uint8')-f3)*(255/(c3-f3));

% map the channels to the RGB frame for display
frame(:,:,1) = M(1,1)*ch1 + M(1,2)*ch2 + M(1,3)*ch3;
frame(:,:,2) = M(2,1)*ch2 + M(2,2)*ch2 + M(2,3)*ch3;
frame(:,:,3) = M(3,1)*ch3 + M(3,2)*ch2 + M(3,3)*ch3;

image(frame)

Subject: Re: load & display multichannel images quickly

From: Peter Boettcher

Date: 08 May, 2008 20:42:23

Message: 2 of 5

"jay vaughan" <jvaughan5.nospam@gmail.com> writes:

> Hi again,
>
> I am trying to optimize the speed of loading in three
> MxN arrays and assigning them to an 8 bit MxNx3 array
> (RGB) to be displayed.
>
> It's a sensitive part of a GUI I am working on, but
> I am having trouble optimizing it. A shortened version of
> the code is at the bottom.
>
> One problem is that if the floor and ceiling inputs,
> (contrast/brightness parameters), are doubles then
> MATLAB executes the code too slowly I presume since
> it is converting the term (255/(c1-f1)) from double
> to uint8. If the floor and ceiling inputs are uint8,
> MATLAB executes the code more quickly but then
> rounds the factor (255/(c1-f1)) before multiplying,
> which reduces the bit depth of the contrast pretty
> badly.
>
> The speed is close to what I need (a factor of 2
> improvement would be great), but I am not sure how
> to speed things up further.
>
> Sometimes when I find myself in this kind of pickle
> it means I am going about the problem the wrong way.
> For instance, is there be a better solution with
> some clever way of adjusting the colormapping
> rather than adjusting the data itself?
>
> Thanks,
> J
>
> % initialize frame
> frame_size = [256 256];
> frame = zeros(frame_size(1),frame_size(2),3,'uint8');
>
> % get floor & ceiling inputs (min & max in data channels)
> f1 = 10; f2 = 10; f3 = 10;
> c1 = 10; c2 = 10; c3 = 10;
>
> % M maps data channels (row) to RGB weight (column)
> M = [1 0 0; 0 1 0; 0 0 1];
>
> % read in the three data channels
> ch1 = (fread(fid1, frame_size, '*uint8')-f1)*(255/(c1-f1));
> ch2 = (fread(fid2, frame_size, '*uint8')-f2)*(255/(c2-f2));
> ch3 = (fread(fid3, frame_size, '*uint8')-f3)*(255/(c3-f3));
>
> % map the channels to the RGB frame for display
> frame(:,:,1) = M(1,1)*ch1 + M(1,2)*ch2 + M(1,3)*ch3;
> frame(:,:,2) = M(2,1)*ch2 + M(2,2)*ch2 + M(2,3)*ch3;
> frame(:,:,3) = M(3,1)*ch3 + M(3,2)*ch2 + M(3,3)*ch3;
>
> image(frame)

You're right, casts to and from floating point are very slow. I would
stay in integer, but expand to an integer, do the operations, and return
to uint8. Careful with the operation ordering.

f1 = uint32(10);
c1 = uint32(100);

t = fread(fid1, frame_size, '*uint8');
ch1 = (uint32(255) * (uint32(t) - f1)) / (c1 - f1)

By doing the multiply by 255 first, you don't have any precision
problems, and the uint32 can hold the full range.

Actually, you're even better off calculating the gain as a fixed
point value, so that each operation is only a multiply followed by a
power-of-2 divide. Hopefully MATLAB does a shift for an integer
power-of-2 divide. If not, do it yourself with "bitshift".

gain = uint32(256*256) / (c1 - f1);

ch1 = gain * (uint32(t) - f1) / 256;


-Peter

Subject: Re: load & display multichannel images quickly

From: jay vaughan

Date: 08 May, 2008 22:57:03

Message: 3 of 5

Peter Boettcher <boettcher@ll.mit.edu> wrote in message
<muy63toh6j4.fsf@G99-Boettcher.llan.ll.mit.edu>...
> "jay vaughan" <jvaughan5.nospam@gmail.com> writes:
>
> > Hi again,
> >
> > I am trying to optimize the speed of loading in three
> > MxN arrays and assigning them to an 8 bit MxNx3 array
> > (RGB) to be displayed.
> >
> > It's a sensitive part of a GUI I am working on, but
> > I am having trouble optimizing it. A shortened version of
> > the code is at the bottom.
> >
> > One problem is that if the floor and ceiling inputs,
> > (contrast/brightness parameters), are doubles then
> > MATLAB executes the code too slowly I presume since
> > it is converting the term (255/(c1-f1)) from double
> > to uint8. If the floor and ceiling inputs are uint8,
> > MATLAB executes the code more quickly but then
> > rounds the factor (255/(c1-f1)) before multiplying,
> > which reduces the bit depth of the contrast pretty
> > badly.
> >
> > The speed is close to what I need (a factor of 2
> > improvement would be great), but I am not sure how
> > to speed things up further.
> >
> > Sometimes when I find myself in this kind of pickle
> > it means I am going about the problem the wrong way.
> > For instance, is there be a better solution with
> > some clever way of adjusting the colormapping
> > rather than adjusting the data itself?
> >
> > Thanks,
> > J
> >
> > % initialize frame
> > frame_size = [256 256];
> > frame = zeros(frame_size(1),frame_size(2),3,'uint8');
> >
> > % get floor & ceiling inputs (min & max in data channels)
> > f1 = 10; f2 = 10; f3 = 10;
> > c1 = 10; c2 = 10; c3 = 10;
> >
> > % M maps data channels (row) to RGB weight (column)
> > M = [1 0 0; 0 1 0; 0 0 1];
> >
> > % read in the three data channels
> > ch1 = (fread(fid1, frame_size, '*uint8')-f1)*(255/(c1-f1));
> > ch2 = (fread(fid2, frame_size, '*uint8')-f2)*(255/(c2-f2));
> > ch3 = (fread(fid3, frame_size, '*uint8')-f3)*(255/(c3-f3));
> >
> > % map the channels to the RGB frame for display
> > frame(:,:,1) = M(1,1)*ch1 + M(1,2)*ch2 + M(1,3)*ch3;
> > frame(:,:,2) = M(2,1)*ch2 + M(2,2)*ch2 + M(2,3)*ch3;
> > frame(:,:,3) = M(3,1)*ch3 + M(3,2)*ch2 + M(3,3)*ch3;
> >
> > image(frame)
>
> You're right, casts to and from floating point are very
slow. I would
> stay in integer, but expand to an integer, do the
operations, and return
> to uint8. Careful with the operation ordering.
>
> f1 = uint32(10);
> c1 = uint32(100);
>
> t = fread(fid1, frame_size, '*uint8');
> ch1 = (uint32(255) * (uint32(t) - f1)) / (c1 - f1)
>
> By doing the multiply by 255 first, you don't have any
precision
> problems, and the uint32 can hold the full range.
>
> Actually, you're even better off calculating the gain as a
fixed
> point value, so that each operation is only a multiply
followed by a
> power-of-2 divide. Hopefully MATLAB does a shift for an
integer
> power-of-2 divide. If not, do it yourself with "bitshift".
>
> gain = uint32(256*256) / (c1 - f1);
>
> ch1 = gain * (uint32(t) - f1) / 256;
>
>
> -Peter


Hi Peter,

thanks for the suggestions. I tried to implement them but it
didn't improve things. Perhaps I implemented them
incorrectly? (See attempts 3 & 4.)

% attempt 1: speed ok (0.0137 sec) but poor gain resolution
f1 = 10;
c1 = 10;
ch1 = (fread(fid1, frame_size, '*uint8')-f1)*(255/(c1-f1));

% attempt 2: slow (0.025 sec) but poor gain resolution
f1 = 10;
c1 = 10;
ch1=(fread(fid1,frame_size,'*uint8')-f1)*(255/double(c1-f1));

% attempt 3: slow (0.025 sec) but poor gain resolution
f1 = uint32(10);
c1 = uint32(10);
ch1 =
uint8(uint32(255)*(uint32(fread(fid1,frame_size,'*uint8')-f1)/(c1-f1)));

% attempt 4: slow (0.025 sec) but has good gain resolution
f1 = uint32(10); % MATLAB f1 & c1 to be uint32 not uint8
c1 = uint32(10);
gain = uint32(256*256)/(channel_ceiling-channel_floor);
ch1=uint8(gain*(uint32(fread(fid,frame_size,'*uint8'))-f)/256);

Subject: Re: load & display multichannel images quickly

From: Peter Boettcher

Date: 09 May, 2008 12:59:40

Message: 4 of 5

"jay vaughan" <jvaughan5.nospam@gmail.com> writes:

> thanks for the suggestions. I tried to implement them but it
> didn't improve things. Perhaps I implemented them
> incorrectly? (See attempts 3 & 4.)
>
> % attempt 1: speed ok (0.0137 sec) but poor gain resolution
> f1 = 10;
> c1 = 10;
> ch1 = (fread(fid1, frame_size, '*uint8')-f1)*(255/(c1-f1));
>
> % attempt 2: slow (0.025 sec) but poor gain resolution
> f1 = 10;
> c1 = 10;
> ch1=(fread(fid1,frame_size,'*uint8')-f1)*(255/double(c1-f1));
>
> % attempt 3: slow (0.025 sec) but poor gain resolution
> f1 = uint32(10);
> c1 = uint32(10);
> ch1 =
> uint8(uint32(255)*(uint32(fread(fid1,frame_size,'*uint8')-f1)/(c1-f1)));
>
> % attempt 4: slow (0.025 sec) but has good gain resolution
> f1 = uint32(10); % MATLAB f1 & c1 to be uint32 not uint8
> c1 = uint32(10);
> gain = uint32(256*256)/(channel_ceiling-channel_floor);
> ch1=uint8(gain*(uint32(fread(fid,frame_size,'*uint8'))-f)/256);

Try bitshift(gain*(uint32(fread(fid,frame_size,'*uint8'))-f), -8)
instead of /256

Other than that, your only other option might be a MEX file

-Peter

Subject: Re: load & display multichannel images quickly

From: jay vaughan

Date: 09 May, 2008 21:52:03

Message: 5 of 5

Peter Boettcher <boettcher@ll.mit.edu> wrote in message
<muy1w4bhbur.fsf@G99-Boettcher.llan.ll.mit.edu>...
> "jay vaughan" <jvaughan5.nospam@gmail.com> writes:
>
> > thanks for the suggestions. I tried to implement them but it
> > didn't improve things. Perhaps I implemented them
> > incorrectly? (See attempts 3 & 4.)
> >
> > % attempt 1: speed ok (0.0137 sec) but poor gain resolution
> > f1 = 10;
> > c1 = 10;
> > ch1 = (fread(fid1, frame_size, '*uint8')-f1)*(255/(c1-f1));
> >
> > % attempt 2: slow (0.025 sec) but poor gain resolution
> > f1 = 10;
> > c1 = 10;
> >
ch1=(fread(fid1,frame_size,'*uint8')-f1)*(255/double(c1-f1));
> >
> > % attempt 3: slow (0.025 sec) but poor gain resolution
> > f1 = uint32(10);
> > c1 = uint32(10);
> > ch1 =
> >
uint8(uint32(255)*(uint32(fread(fid1,frame_size,'*uint8')-f1)/(c1-f1)));
> >
> > % attempt 4: slow (0.025 sec) but has good gain resolution
> > f1 = uint32(10); % MATLAB f1 & c1 to be uint32 not uint8
> > c1 = uint32(10);
> > gain = uint32(256*256)/(channel_ceiling-channel_floor);
> >
ch1=uint8(gain*(uint32(fread(fid,frame_size,'*uint8'))-f)/256);
>
> Try
bitshift(gain*(uint32(fread(fid,frame_size,'*uint8'))-f), -8)
> instead of /256
>
> Other than that, your only other option might be a MEX file
>
> -Peter


Hi Peter,

thanks for spelling out the bitshift operation for me. It
helped! I got things down to about 0.019 sec with good gain
resolution, compared to approach 1 with 0.014 sec with poor
gain resolution or approaches 2-4 with good gain resolution
but 0.025 sec duration. 0.014 is barely a compromise! (FYI I
had to operate on the bitshift result with uint8 before
putting the result into the 8-bit RGB array.)

I am still wondering about doing this task more quickly, but
can move on to other issues for the moment. I haven't played
with MEX files before, but would consider doing so depending
on what benefit there might be.

Thanks,
J

Tags for this Thread

Everyone's Tags:

Add a New Tag:

Separated by commas
Ex.: root locus, bode

What are tags?

A tag is like a keyword or category label associated with each thread. Tags make it easier for you to find threads of interest.

Anyone can tag a thread. Tags are public and visible to everyone.

Tag Activity for This Thread
Tag Applied By Date/Time
multichannel images jay vaughan 08 May, 2008 15:10:20
rssFeed for this Thread

envelope graphic E-mail this page to a colleague

Public Submission Policy
NOTICE: Any content you submit to MATLAB Central, including personal information, is not subject to the protections which may be afforded information collected under other sections of The MathWorks, Inc. Web site. You are entirely responsible for all content that you upload, post, e-mail, transmit or otherwise make available via MATLAB Central. The MathWorks does not control the content posted by visitors to MATLAB Central and, does not guarantee the accuracy, integrity, or quality of such content. Under no circumstances will The MathWorks be liable in any way for any content not authored by The MathWorks, or any loss or damage of any kind incurred as a result of the use of any content posted, e-mailed, transmitted or otherwise made available via MATLAB Central. Read the complete Disclaimer prior to use.
Related Topics