Fast Image Thresholding-will a mex file improve speed?

I have some image/video processing code where on each frame I have to threshold it about 3 different times. Right now I simply use...
while(1)
im = getsnapshot; %returns a uint8 640X480 array
im1 = im>50&im<100; %example thresholds
im2 = im >100&im<150;
im3 = im>150&im<200;
%lots more image processing
end
______
I have made the remainder of the code so efficient that at this point, most of the time is spent on the thresholding lines. Any tips to make this faster? (FYI im2bw is much slower).
Is this a situation where a Mex File could improve performance? I know a lot has changes in the last few versions of matlab to make it much faster so I am wondering if its worth mex-ing?
Thanks, Joel

 Réponse acceptée

Jan
Jan le 15 Août 2011
Yes, this will be faster as C-Mex.
im1 = im > 50 & im < 100
Here at first a 640x480 LOGICAL matrix is calculated in "im > 50". Then a 2nd matrix is created for "im < 100". But is a pixels is <= 50, the test for > 100 is a waste if time. Most of all if the different intervals are not overlapping a lot of time can be saved by avoiding unnecessary tests.
Before I post a C-code, it would be helpful to know, if the intervals are continous, in opposite to your example. E.g. 50 < im < 100, 100 <= im < 150, 150 <= im < 200? Or is im==100 exluded on purpose?
[TEST-IMPLEMENTATION UNTIL QUESTIONS ARE CLEARED]: I assume, that the intervals are dense here.
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
uint8_T *im, limit1, limit2, limit3, limit4, p;
mxLogical *im1, *im2, *im3;
mwSize m, n, len;
mwIndex i;
// Check inputs:
if (nrhs != 5 || nlhs != 3) {
mexErrMsgIdAndTxt("JSimon:ImInterval:BadNArgs",
"Need 5 inputs and 3 outputs.");
}
if (!mxIsUint8(prhs[0])) {
mexErrMsgIdAndTxt("JSimon:ImInterval:BadTypeInput1",
"1st input must be an UINT8 matrix.");
}
// Get size of input and pointer to data:
m = mxGetM(plhs[0]);
n = mxGetN(plhs[0]);
im = (uint8_T *) mxGetData(prhs[0]);
len = m * n;
limit1 = (uint8_T) mxGetScalar(prhs[1]);
limit2 = (uint8_T) mxGetScalar(prhs[2]);
limit3 = (uint8_T) mxGetScalar(prhs[3]);
limit4 = (uint8_T) mxGetScalar(prhs[4]);
// Create outputs:
plhs[0] = mxCreateNumericMatrix(m, n, mxLOGICAL_CLASS, mxREAL);
im1 = (mxLogical *) mxGetData(plhs[0]);
plhs[1] = mxCreateNumericMatrix(m, n, mxLOGICAL_CLASS, mxREAL);
im2 = (mxLogical *) mxGetData(plhs[1]);
plhs[2] = mxCreateNumericMatrix(m, n, mxLOGICAL_CLASS, mxREAL);
im3 = (mxLogical *) mxGetData(plhs[2]);
// The calculations:
for (i = 0; i < len; i++) {
p = im[i];
if (p > limit1) {
if (p < limit2) {
im1[i] = 1;
} else if (p < limit3) {
im2[i] = 1;
} else if (p < limit4) {
im3[i] = 1;
}
}
}
return;
}

8 commentaires

Joel
Joel le 15 Août 2011
Thanks for the quick reply! As you stated, I suspected there might be some reduncance there.
I simplified the example a bit to make it readable... In general, what I'd really like to do is make a functon something like this:
[im1, im2, im3] = FastSegmentThreeColors(im, Thresholds3, Thresholds2, Thresholds3)
Where im is a color image (640X480X3 uint8)
and each Threshold is a vector of 6 numbers: [redLow, redHigh, greenLow, greenHigh, blueLow, blueHigh].
The three outputs are class logical (eg binary images with 1's marking the pixels meeting the cooresponding thresholds).
The Thresholds1, Thresholds2, Thresholds3 do not have any particular interrelationship (ex they are not nessecarily mutually exclusive).
Joel
Joel le 15 Août 2011
I see you already posted code. Amazing! I can work off of that.
Thanks!
Joel
Joel le 15 Août 2011
Just a Follow Up:
I discoverd that on my machine, even a matlab function that uses the for loop approach is faster than the original syntax! I didn't expect that since the traditional wisdom is that forloops are slow.
Thanks again, Joel
Jan
Jan le 15 Août 2011
@Joel: I've been too fast. In opposite to your original question, the data are in RGB format. And the limits are *not* dense. This demands for more comparisons and it is not possible to use the information that the value is below the first limit to avoid the other comparisons.
It will be a benefit, if the array is processed in contiguos blocks. So process the R channel at first, then G and B.
I assume, my Mex-conversion would have been more matching, if you had posted the working M-function. Feel free to ask for further assistence on demand.
Joel
Joel le 16 Août 2011
Can you show me an example of what you mean for a color image? (how would the if statements be structured?
Thanks.
Jan
Jan le 16 Août 2011
@Joel: The rumors about slow FOR loops concern MATLAB <= 5.3. Can you post the M-implementation of the code? Then it will be more likely, that my examples will match.
Joel
Joel le 16 Août 2011
function [imb1, imb2, imb3] = FastThresholdThreeColor(im, t1, t2, t3)
% Quick image thresholding of three colors
% im is an uint8 color image (YCbCr)
% t1, t2, t3 are 6 element vectors that list the low and high threshold on
% each channel ex t1 = [Ylo, Yhi, CbLo, CbHi, CrLo, CrHi];
% I decided to make thresholds mutually exclusive
s = size(im);
imb1 = false(s(1), s(2));
imb2 = false(s(1), s(2));
imb3 = false(s(1), s(2));
for i = 1:s(2) % each column...going down a column is supposed to be faster?
for j =1:s(1) % down a row
% note that intentionally make channel 1 last to exploit
% shortcircuit (its usually the least restrictive)
if im(j,i,2)>=t1(3) && im(j,i,2)<=t1(4) && ...
im(j,i,3)>=t1(5) && im(j,i,3)<=t1(6)&&...
im(j,i,1)>=t1(1) && im(j,i,1)<=t1(2)
imb1(j,i) =1;
elseif im(j,i,2)>=t2(3) && im(j,i,2)<=t2(4) && ...
im(j,i,3)>=t2(5) && im(j,i,3)<=t2(6)&& ...
im(j,i,1)>=t2(1) && im(j,i,1)<=t2(2)
imb2(j,i) =1;
elseif im(j,i,2)>=t3(3) && im(j,i,2)<=t3(4) && ...
im(j,i,3)>=t3(5) && im(j,i,3)<=t3(6)&& ...
im(j,i,1)>=t3(1) && im(j,i,1)<=t3(2)
imb3(j,i) =1;
end
end
end
Joel
Joel le 22 Août 2011
Any more thoughts on how the color version shoudl be structured to optimize performance?

Connectez-vous pour commenter.

Plus de réponses (1)

Chirag Gupta
Chirag Gupta le 15 Août 2011

0 votes

You can also use manual trigger mode on your videoinput object to reduce the overhead associated with getsnapshot.
Check the "Acquiring a Single Image in a Loop" demo in the documentation

3 commentaires

Joel
Joel le 15 Août 2011
Thanks. I already do.
Joel
Joel le 16 Août 2011
While I do that currently, I am not convinced it is the festeest possible way. Of course its an order of magnitude better that using the default trigger setting but have you experimented with setting teh frames per trigget to infinite and then using peekdata?
What about using a callback function?
Joel
Joel le 22 Août 2011
Any more thoughts?

Connectez-vous pour commenter.

Catégories

En savoir plus sur Scope Variables and Generate Names dans Centre d'aide et File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by