Exposed concrete must meet several requirements. Technological, structural and functional requirements are already standardized and designers refer to various Belgian and European standards.
The WTCB -CSTC (1) is standardizing aesthetic requirements of exposed concrete. These requirements relate to the texture, the number and size of the bubbles and the homogeneity of the color. This standard is an extension of the standard EN 206-1 , NBN B 15-001 and DIN EN 13670 .
The next image processing intends to measure the surface proportion of bubbles less than 2 mm, bubbles of 2 to 15 mm and bubbles over 15 mm ( defects) . According to the surface percentage of bubbles of 2 to 15 mm, it will be standard, high quality or high quality.
0-2mm Bubbles in blue, 2-15mm bubbles in green, defaults in red.
Click on the image to see the animated gif
The threshold used the Otsu algorithm optimized to cut bimodal (black and white) distribution of pixels.
Nevertheless to give good result the image has to be cleaned of non-uniform lighting and non-uniform concrete texture and color.
This is done by removing the background from the image. This background is provided by a morphological closing and better by a morphological erosion followed by a reconstruction (2).
Matlab code :
function [Sum_0_2, Sum_2_15, Sum_15_max] = GetConcretePorosity( image_path ) % GetConcretePorosity % Computes the Porosity of concrete surface % Norm definition : % Standard Concrete : < 1,9% of 2-15mm bubbles; % HT Concrete : < 0,6% of 2-15mm bubbles % THT Concrete : <0,3% of 2-15mm bubbles % Usage: % [Sum_0_2, Sum_2_15, Sum_15_max] = ... % GetConcretePorosity('C:/Image-Acquisition/Bulles/Fotos/P1080135.JPG'); % 1 - read the image Im_Color = imread(image_path); crop_option = 0; if crop_option == 1 [Im_Color] = imcrop(Im_Color); end % rgb2gray converts RGB images to grayscale by eliminating the hue and % saturation information while retaining the luminance Im_Gray = rgb2gray(Im_Color); % 2 - read the resolution % note : 72dpi means 1 pixel = 25.4/72 mm = 0,35 mm info=imfinfo(image_path); XResolution = info.XResolution; Area_2mm = int32((3.1416/4)*(2*XResolution/25.4)^2); Area_15mm = int32((3.1416/4)*(15*XResolution/25.4)^2); % 3 - remove the background % remove what is smaller than 15mm : 15 x 72 / 25.4 pixels cutoff_size_mm = 15; SE_size = (cutoff_size_mm*XResolution/25.4)/2; %structuring_element = strel('disk', 20); structuring_element = strel('disk', double(uint8(SE_size))); remove_option = 2; if remove_option == 1 Im_Closed = imclose(Im_Gray, structuring_element); Im_Corrected = imadjust(Im_Closed - Im_Gray); else Im_Gray_Complement = imcomplement(Im_Gray); Im_Marker = imerode(Im_Gray_Complement, structuring_element); Im_Reconstructed = imreconstruct(Im_Marker, Im_Gray_Complement); Im_Closed = imcomplement(Im_Reconstructed); Im_Corrected = imadjust(Im_Closed - Im_Gray); end %figure; %imshow(imcomplement(Im_Corrected)); % 4 - the segmentation % The graythresh function uses Otsu's method, which chooses the threshold % to minimize the intraclass variance of the black and white pixels. level = graythresh(Im_Corrected); Im_Segmented = im2bw(Im_Corrected,level); Im_Segmented = imfill(Im_Segmented,'holes'); % Remove particle smaller than 2mm with bwareaopen : % BW2 = bwareaopen(BW, P) removes from a binary image all connected % components (objects) that have fewer than P pixels % Im_Segmented = imclose(Im_Segmented, 15); cc = bwconncomp(Im_Segmented, 8); cc.NumObjects; labeled = labelmatrix(cc); % RGB_label = label2rgb(labeled, @spring, 'c', 'shuffle'); % figure, imshow(RGB_label); graindata = regionprops(cc, 'basic'); regions_areas = [graindata.Area]; % 5 - make 3 groups of bubbles 0-2, 2-15, 15-max mm % sort the areas then the indexes [grain_areas, label_idx] = sort(regions_areas); [label_idx_s, label_idx_s_idx] = sort(label_idx); % remove the background region % grain_areas(end) = ; index_2mm = -1; index_15mm = -1; for i = 1:length(grain_areas) if all([grain_areas(i)>Area_2mm, index_2mm == -1]) index_2mm = i; end if all([grain_areas(i)>Area_15mm, index_15mm == -1]) index_15mm = i; end end % 6 - Create a animated gif Im_Color_Overlay = Im_Color; [Width, Height] = size(Im_Segmented); for j=1:Height for i=1:Width if labeled(i, j) ~= 0 label_ij = labeled(i, j); label_idx_ij = label_idx_s_idx(label_ij); % Im_Color(i,j,:) = [255, 0, 255]; if label_idx_ij < index_2mm Im_Color_Overlay(i,j,3) = 255; elseif label_idx_ij < index_15mm Im_Color_Overlay(i,j,2) = 255; else Im_Color_Overlay(i,j,1) = 255; end end end end filename = 'C:/Image-Acquisition/Concrete_Bubbles.gif'; [Im_Color_Overlay_256, Im_Color_Overlay_Map] = ... rgb2ind(Im_Color_Overlay, 256); Im_Color_Overlay_256(:,:,1,2) = rgb2ind(Im_Color, Im_Color_Overlay_Map); imwrite(Im_Color_Overlay_256, Im_Color_Overlay_Map, filename, 'DelayTime', 1, ... 'LoopCount', inf); %imwrite(Im_Color_Overlay_256, Im_Color_Overlay_Map, filename, 'gif', ... % 'DelayTime', 1, 'Loopcount',inf); %imwrite(Im_Color_Overlay_256, Im_Color_Overlay_Map, filename, 'gif', ... % 'WriteMode', 'append'); figure, imshow(Im_Color); % 7 output histograms and surfaces ratio grain_areas = grain_areas(index_2mm:index_15mm); grain_size = sqrt(grain_areas/3.1416); x_bins = [0, 2, 15, 50]; figure; s(1) = subplot(2,1,1); s(2) = subplot(2,1,2); hist(s(1), grain_size, x_bins); hist(s(2), grain_size, 20); Sum_0_2 = sum(regions_areas(1:index_2mm))/(Width*Height); Sum_2_15 = sum(regions_areas(index_2mm:index_15mm))/(Width*Height); Sum_15_max = sum(regions_areas(index_15mm:length(grain_areas)))/(Width*Height); end
(1) The WTCB -CSTC is a research institute funded primarily by 90000 Belgian companies representing all construction trades , which leads scientific and technical research for the benefit of its members, providing technical advice and contributing to innovation in order to improve the competitiveness of these.