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?
> 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.
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".
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);
> 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 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.
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.