# extracting mean pixel value from an image

31 views (last 30 days)

Show older comments

I would like to extract the mean pixel value on the image.

I would like to do it automatic by locating the brightess point next to the green rectangular point coordinates, cropping the new coordinates and finding its mean pixel vaules

##### 0 Comments

### Accepted Answer

DGM
on 20 May 2022

Edited: DGM
on 20 May 2022

This might be a start, but bear in mind how fragile this will be if the colors change or the swatch becomes rotated or something.

A = imread('https://www.mathworks.com/matlabcentral/answers/uploaded_files/1004350/Picture1.png');

Ahsv = rgb2hsv(A);

[H S V] = imsplit(Ahsv);

mask = S>0.9 & H>0.15; % create mask

mask = bwareaopen(mask,100); % despeckle

% use a large strel to bridge dotted lines

% this assumes that lines are roughly grid-aligned

stlen = 200;

mask = imopen(~mask,ones(stlen));

% erode to avoid including any green bits on edges

mask = imerode(mask,ones(10));

% this assumes that the largest blob is the ROI

mask = bwareafilt(mask,1);

imshow(mask)

% build an Mx3 color table from the pixels in the ROI

roipix = zeros(nnz(mask),3,class(A));

for c = 1:3 % assumes A is RGB

thischan = A(:,:,c);

roipix(:,c) = thischan(mask);

end

% find the mean color

meancolor = mean(roipix,1)

% for visualization of the nonsquare ROI

% fill non-ROI with black

rgbpict = A;

rgbpict(repmat(~mask,[1 1 3])) = 0;

% pad the modified image with a color swatch

sz = size(A);

meanswatch = repmat(permute(meancolor,[1 3 2]),[50 sz(2) 1]);

meanswatch = uint8(meanswatch);

outpict = [rgbpict; meanswatch];

imshow(outpict)

Note that's just the simple arithmetic mean. It might not be what you want, considering how it will be influenced by the light bleed and the vignetting. Alternatively, you might try using median() instead of mean.

% get some different image stats from the ROI

cc = imstats(ctflop(roipix),'mean','median','mode','modecolor','modefuzzy','moderange','nmost',10);

% use those stats to construct a swatch chart for single-output stats

labels = {'mean','median','mode','modecolor','modefuzzy'};

sz = imsize(rgbpict,2);

ntiles = (numel(labels));

tilesz = [round(sz(1)/ntiles) 100];

block1 = zeros([tilesz 3 ntiles],'uint8');

for k = 1:ntiles

thistile = colorpict([tilesz 3],cc(k,:),'uint8'); % colored swatch

thislabel = im2uint8(1-textim(labels{k},'ibm-iso-16x9')); % text label image

thistile = im2uint8(imstacker({thislabel thistile},'padding',1)); % match geometry

block1(:,:,:,k) = mergedown(thistile,1,'linearburn'); % blend label and swatch

end

block1 = imtile(block1,[ntiles 1]); % vertically arrange tiles

block1 = imresize(block1,[sz(1) tilesz(2)]); % make sure it's the right size

% create another chart for moderange's multiple outputs

ntiles = (size(cc,1)-ntiles);

tilesz = [round(sz(1)/ntiles) 100];

block2 = zeros([tilesz 3 ntiles],'uint8');

for k = 1:ntiles

thistile = colorpict([tilesz 3],cc(k+4,:),'uint8'); % colored swatch

thislabel = im2uint8(1-textim(num2str(k),'ibm-iso-16x9')); % text label image

thistile = im2uint8(imstacker({thislabel thistile},'padding',1)); % match geometry

block2(:,:,:,k) = mergedown(thistile,1,'linearburn'); % blend label and swatch

end

block2 = imtile(block2,[ntiles 1]); % vertically arrange tiles

block2 = imresize(block2,[sz(1) tilesz(2)]); % make sure it's the right size

% show the combined images

imshow([rgbpict block1 block2])

Make of that what you will. See the linked answer for more details on these options.

##### 25 Comments

DGM
on 2 Jun 2022

Edited: DGM
on 4 Jun 2022

This might not actually be too bad. It works for all the given images so far without any consideration of the marker dots. You can tweak the angle tolerance quite a bit. I modified one of the images to demonstrate that it still works even if there's quite a bit of distortion.

% the input image

A = imread('10A_22_skew.jpg');

% get mask of all light peaks

peakmask = mean(A,3)>210; % HSI intensity

peakmask = imclearborder(peakmask);

peakmask = bwareaopen(peakmask,100);

imshow(peakmask); hold on

% get centroids

S = regionprops(peakmask,'centroid');

Cpeaks = vertcat(S.Centroid);

Cimg = fliplr(size(peakmask))/2;

% find the peak closest to the image center

D = sqrt(sum((Cpeaks-Cimg).^2,2));

[~,idx] = min(D);

Ccenter = Cpeaks(idx,:);

% mark the center peak

plot(Ccenter(1),Ccenter(2),'r*','linewidth',2)

% find the 8 peaks closest to this peak

D = sqrt(sum((Cpeaks-Ccenter).^2,2));

[~,idx] = mink(D,9);

Cnh = Cpeaks(idx(2:end),:); % ignore self-distance

% find points which are oriented roughly 45

thtol = 16; % allowable angle deviation from 45

thc = atan2d(Cnh(:,2)-Cimg(1,2),Cnh(:,1)-Cimg(1,1));

th = mod(thc,90);

idxc = th>(45-thtol) & th<(45+thtol); % find angles which are roughly multiples of 45

Ccorners = Cnh(idxc,:); % there should only be 4 rows here

thc = thc(idxc);

% walk outwards along those diagonal trajectories

sqsize = 9; % the square is 9x9 points

for kann = 1:floor(sqsize/2)-1

for k = 1:4 % assuming Ccorners has 4 rows

% find the 8 peaks closest to this peak

thiscorner = Ccorners(k,:);

D = sqrt(sum((Cpeaks-thiscorner).^2,2));

[~,idx] = mink(D,9);

Cnh = Cpeaks(idx(2:end),:); % ignore self-distance

% find point which is oriented roughly in the same direction

% as the prior point was oriented WRT to the image center

th = atan2d(Cnh(:,2)-thiscorner(1,2),Cnh(:,1)-thiscorner(1,1));

[~,idx] = min(abs(th-thc(k)));

Ccorners(k,:) = Cnh(idx,:); % there should only be one row here

thc(k) = th(idx);

end

end

% show where the estimated corners are

plot(Ccorners(:,1),Ccorners(:,2),'mo','linewidth',2,'markersize',20)

% sort by angle

[~,idx] = sort(thc,'ascend');

Ccorners = Ccorners(idx,:);

% create polygonal ROI object

ROI = images.roi.Polygon(gca);

ROI.Position = Ccorners;

At that point, you could use createMask() as before to get a logical mask from ROI, or whatever else is needed.

### More Answers (3)

DGM
on 4 Jun 2022

I was assuming that the green marks weren't going to be the ROI delimiters anymore, but if they still are, you can't use image geometry to estimate the ROI center. You still have to deal with finding the marks -- but maybe you can get away without needing to do as much masking.

Still, finding the region center is questionable if there's significant perspective distortion. I slapped it in a loop and made it at least try to fix itself if it runs into the edge of the image, but I don't doubt that this can still break easily. It works for all the images so far at least. It doesn't seem too picky about the masking yet.

% the input image

%A = imread('Picture1.png');

%A = imread('picture4.jpg');

%A = imread('40A_12.jpg');

%A = imread('25A_13.jpg');

%A = imread('10A_22.jpg');

%A = imread('10A_22_skew.jpg');

A = imread('40A_23.jpg');

sqsize = 9; % the square is 9x9 points

thtol = 15; % allowable angle deviation from 45

% try to find dark-ish areas that might be marks

V = max(A,[],3);

roimask = V<100;

roimask = bwareaopen(roimask,100); % despeckle

% find the point that's furthest away from any dark spots

D = bwdist(roimask);

[mx,idx] = max(D(:));

[r c] = ind2sub(size(D),idx);

Cimg = [c r];

% get mask of all light peaks

peakmask = mean(A,3)>200; % HSI intensity

peakmask = imclearborder(peakmask);

peakmask = bwareaopen(peakmask,100);

imshow(peakmask); hold on

% get centroids

S = regionprops(peakmask,'centroid');

Cpeaks = vertcat(S.Centroid);

% distance from every object to every other object

D = sqrt((Cpeaks(:,1)-Cpeaks(:,1).').^2 + (Cpeaks(:,2)-Cpeaks(:,2).').^2);

D(D<1E-6) = NaN; % remove self-distances

Dmean = mean(min(D,[],2)); % average grid spacing

% try to find corners

% if we run into the image edges, adjust center and try again

% adjust at most twice before continuing/failing

Ccorrection = 0;

for attempt = 1:3

[Ccorners thc Ccorrection] = findcorners(Cpeaks,Cimg,sqsize,thtol);

if Ccorrection == 0; break; end

if attempt == 1

% distance from every object to every other object

D = sqrt((Cpeaks(:,1)-Cpeaks(:,1).').^2 + (Cpeaks(:,2)-Cpeaks(:,2).').^2);

D(D<1E-6) = NaN; % remove self-distances

Dmean = mean(min(D,[],2)); % average grid spacing

end

% adjust estimate of image center

Cimg(2) = Cimg(2) - Ccorrection*Dmean;

end

% show where the estimated corners are

plot(Ccorners(:,1),Ccorners(:,2),'mo','linewidth',2,'markersize',20)

% show ROI on original image

figure

imshow(A); hold on

% sort by angle

[~,idx] = sort(thc,'ascend');

Ccorners = Ccorners(idx,:);

% create polygonal ROI object

ROI = images.roi.Polygon(gca);

ROI.Position = Ccorners;

function [Ccorners thc Ccorrection] = findcorners(Cpeaks,Cimg,sqsize,thtol)

% find the peak closest to the image center

D = sqrt(sum((Cpeaks-Cimg).^2,2));

[~,idx] = min(D);

Ccenter = Cpeaks(idx,:);

% mark the center peak

plot(Ccenter(1),Ccenter(2),'c*')

% find the 8 peaks closest to this peak

D = sqrt(sum((Cpeaks-Ccenter).^2,2));

[~,idx] = mink(D,9);

Cnh = Cpeaks(idx(2:end),:); % ignore self-distance

% find points which are oriented roughly 45

thc = atan2d(Cnh(:,2)-Cimg(1,2),Cnh(:,1)-Cimg(1,1));

th = mod(thc,90);

idxc = th>(45-thtol) & th<(45+thtol); % find angles which are roughly multiples of 45

Ccorners = Cnh(idxc,:); % there should only be 4 rows here

thc = thc(idxc);

% walk outwards along those diagonal trajectories

for kann = 1:floor(sqsize/2)-1

for k = 1:4 % assuming Ccorners has 4 rows

% find the 8 peaks closest to this peak

thiscorner = Ccorners(k,:);

D = sqrt(sum((Cpeaks-thiscorner).^2,2));

[~,idx] = mink(D,9);

Cnh = Cpeaks(idx(2:end),:); % ignore self-distance

% find point which is oriented roughly in the same direction

% as the prior point was oriented WRT to the image center

th = atan2d(Cnh(:,2)-thiscorner(1,2),Cnh(:,1)-thiscorner(1,1));

[minth idx] = min(abs(th-thc(k)));

% if there are no neighboring points in this direction,

% that's probably because we just ran into the image edge

if minth > thtol

if thc(k)<0

% if walking downward, try shifting initial center upwards

Ccorrection = -1;

else

% if walking upward, try shifting initial center downward

Ccorrection = 1;

end

return;

else

Ccorrection = 0;

end

% update outputs

Ccorners(k,:) = Cnh(idx,:); % there should only be one row here

thc(k) = th(idx);

end

end

end

If you're cropping out B (and transforming it, etc), you obviously lose information outside of the ROI. You're also losing the exact original values within the ROI, since it's being interpolated. Whether that interpolation is meaningful for your analysis, I don't know.

DGM
on 4 Jun 2022

It seems to work for me. The figure in which the ROI object is created needs to be present and needs to contain only one image.

% the input image

%A = imread('Picture1.png');

%A = imread('picture4.jpg');

%A = imread('40A_12.jpg');

%A = imread('25A_13.jpg');

%A = imread('10A_22.jpg');

%A = imread('10A_22_skew.jpg');

A = imread('40A_23.jpg');

sqsize = 9; % the square is 9x9 points

thtol = 15; % allowable angle deviation from 45

% try to find dark-ish areas that might be marks

V = max(A,[],3);

roimask = V<100;

roimask = bwareaopen(roimask,100); % despeckle

% find the point that's furthest away from any dark spots

D = bwdist(roimask);

[mx,idx] = max(D(:));

[r c] = ind2sub(size(D),idx);

Cimg = [c r];

% get mask of all light peaks

peakmask = mean(A,3)>200; % HSI intensity

peakmask = imclearborder(peakmask);

peakmask = bwareaopen(peakmask,100);

imshow(peakmask); hold on

% get centroids

S = regionprops(peakmask,'centroid');

Cpeaks = vertcat(S.Centroid);

% distance from every object to every other object

D = sqrt((Cpeaks(:,1)-Cpeaks(:,1).').^2 + (Cpeaks(:,2)-Cpeaks(:,2).').^2);

D(D<1E-6) = NaN; % remove self-distances

Dmean = mean(min(D,[],2)); % average grid spacing

% try to find corners

% if we run into the image edges, adjust center and try again

% adjust at most twice before continuing/failing

Ccorrection = 0;

for attempt = 1:3

[Ccorners thc Ccorrection] = findcorners(Cpeaks,Cimg,sqsize,thtol);

if Ccorrection == 0; break; end

if attempt == 1

% distance from every object to every other object

D = sqrt((Cpeaks(:,1)-Cpeaks(:,1).').^2 + (Cpeaks(:,2)-Cpeaks(:,2).').^2);

D(D<1E-6) = NaN; % remove self-distances

Dmean = mean(min(D,[],2)); % average grid spacing

end

% adjust estimate of image center

Cimg(2) = Cimg(2) - Ccorrection*Dmean;

end

% show where the estimated corners are

plot(Ccorners(:,1),Ccorners(:,2),'mo','linewidth',2,'markersize',20)

% show ROI on original image

figure

imshow(A); hold on

% sort by angle

[~,idx] = sort(thc,'ascend');

Ccorners = Ccorners(idx,:);

% create polygonal ROI object

ROI = images.roi.Polygon(gca);

ROI.Position = Ccorners;

% create mask from ROI object

mask = createMask(ROI);

% show mask

figure

imshow(mask)

function [Ccorners thc Ccorrection] = findcorners(Cpeaks,Cimg,sqsize,thtol)

% find the peak closest to the image center

D = sqrt(sum((Cpeaks-Cimg).^2,2));

[~,idx] = min(D);

Ccenter = Cpeaks(idx,:);

% mark the center peak

plot(Ccenter(1),Ccenter(2),'c*')

% find the 8 peaks closest to this peak

D = sqrt(sum((Cpeaks-Ccenter).^2,2));

[~,idx] = mink(D,9);

Cnh = Cpeaks(idx(2:end),:); % ignore self-distance

% find points which are oriented roughly 45

thc = atan2d(Cnh(:,2)-Cimg(1,2),Cnh(:,1)-Cimg(1,1));

th = mod(thc,90);

idxc = th>(45-thtol) & th<(45+thtol); % find angles which are roughly multiples of 45

Ccorners = Cnh(idxc,:); % there should only be 4 rows here

thc = thc(idxc);

% walk outwards along those diagonal trajectories

for kann = 1:floor(sqsize/2)-1

for k = 1:4 % assuming Ccorners has 4 rows

% find the 8 peaks closest to this peak

thiscorner = Ccorners(k,:);

D = sqrt(sum((Cpeaks-thiscorner).^2,2));

[~,idx] = mink(D,9);

Cnh = Cpeaks(idx(2:end),:); % ignore self-distance

% find point which is oriented roughly in the same direction

% as the prior point was oriented WRT to the image center

th = atan2d(Cnh(:,2)-thiscorner(1,2),Cnh(:,1)-thiscorner(1,1));

[minth idx] = min(abs(th-thc(k)));

% if there are no neighboring points in this direction,

% that's probably because we just ran into the image edge

if minth > thtol

if thc(k)<0

% if walking downward, try shifting initial center upwards

Ccorrection = -1;

else

% if walking upward, try shifting initial center downward

Ccorrection = 1;

end

return;

else

Ccorrection = 0;

end

% update outputs

Ccorners(k,:) = Cnh(idx,:); % there should only be one row here

thc(k) = th(idx);

end

end

end

##### 13 Comments

DGM
on 1 Jul 2022

### See Also

### Categories

### Community Treasure Hunt

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

Start Hunting!