I'd like to blur only the text found in some images (potentially-sensitive medical information). I'm struggling to remember how to convert bounding boxes into matrix indices, or whether there is a function that does the following.
img = imread('businessCard.png');
imgOCR = ocr( img )
for idx = 1:numel( imgOCR.Words )
bbox = imgOCR.WordBoundingBoxes( idx, : )
subImg = imcrop( img, bbox )
K = medfilt2( subImg )
%%% How to insert K back into img? something like:
% newImg = iminsert( img, bbox, K );
end

 Akzeptierte Antwort

Image Analyst
Image Analyst am 10 Jun. 2021

0 Stimmen

Somehow you need to create a mask defining where the text is. Once you got that, blur the entire image, and blur the mask also. Then get the new larger mask and assign the blurred image to the original image in the blurred mask. In short, something like
windowSize = 15; % Whatever.
kernel = ones(windowSize, windowSize) / windowSize^2;
% Blur the mask and the image.
blurredImage = conv2(double(grayimage), kernel, 'same');
blurredMask = conv2(double(mask), kernel, 'same');
newMask = blurredMask > 0; % Mask is now bigger since it got blurred.
% Replace original pixels with blurred pixels.
grayImage(newMask) = blurredImage(newMask);
It would be easier to simply erase the image in the mask than to blur the text and replace it.
grayImage(mask) = 0;

8 Kommentare

Dominik Mattioli
Dominik Mattioli am 10 Jun. 2021
Don't you think that creating the mask first requires deriving the indices from the bounding box?
Figured it out. To create a mask, simply use poly2mask:
xi = horzcat( bbox( 1 ), bbox( 1 ), bbox( 1 ) + bbox( 3 ), bbox( 1 ) + bbox( 3 ) );
yi = horzcat( bbox( 2 ), bbox( 2 ) + bbox( 4 ), bbox( 2 ) + bbox( 4 ), bbox( 2 ) );
bw = poly2mask( xi, yi, imgSZ( 1 ), imgSZ( 2 ) );
and then follow Image Analyst's protocol.
Johnal Khow
Johnal Khow am 5 Jan. 2022
Hi! Does using this method in creating a mask allow for multiple instances of bbox?
@Johnal Khow I'm not sure if you can do it in a single call to poly2mask. For simple things like bounding boxes, I'd just have a single binary image and loop over all bounding boxes, writing "true" to the bounding box. Like this:
props = regionprops(mask, 'BoundingBox');
allBB = vertcat(props.BoundingBox);
mask = false(rows, columns);
for k = 1 : length(props)
row1 = ceil(allBB(k, 2));
row2 = floor(allBB(k, 2) + allBB(k, 4));
col1 = ceil(allBB(k, 1));
col2 = floor(allBB(k, 1) + allBB(k, 3));
mask(row1:row2, col1:col2) = true;
end
Hello @Image Analyst! I wanted to ask a question regarding the blurring procedure that was mentioned.
When I tried to implement the technique to blur out some text that I wanted to censor, the output it gave me looked more like highlighted text rather than blurred text.
Here's the output:
I've already looked at a bunch of image blurring techniques, and most of them were the same as the one shown here. There is clearly something that I'm misunderstanding and I hope you can help me with this!
Here is the code that I used:
txtimg = imread('test4.png');
B = size(txtimg);
ocrResults = ocr(txtimg);
arr = ["poem"];
bbox = locateText(ocrResults, arr, 'IgnoreCase', true);
[a,b] = size(bbox);
for i = 1:a
%locate mask
xi = horzcat( bbox( i,1 ), bbox( i,1 ), bbox( i,1) + bbox( i,3 ), bbox( i,1 ) + bbox( i,3 ) );
yi = horzcat( bbox( i,2 ), bbox( i,2 ) + bbox( i,4 ), bbox( i,2 ) + bbox( i,4 ), bbox( i,2 ) );
bw = poly2mask( xi, yi, B(1), B(2));
windowSize = 20;
kernel = ones(windowSize, windowSize) / windowSize^2;
blurredImage = imfilter(txtimg,kernel,'same');
blurredMask = imfilter(bw,kernel,'same');
newMask = blurredMask > 0;
txtimg(newMask) = blurredImage(newMask);
end
imshow(txtimg);
DGM
DGM am 26 Jan. 2022
Bearbeitet: DGM am 26 Jan. 2022
You're only blurring the red channel, but I think there are other issues.
Since I don't have CVT, and I'm working on a screenshot of your image instead of the image itself, I just cut out a bunch of the code so that I could run it. You'll have to add the CVT stuff back in.
txtimg = imread('https://www.mathworks.com/matlabcentral/answers/uploaded_files/874225/image.png');
B = size(txtimg);
windowSize = 20; % doesn't need to be inside loop
kernel = ones(windowSize, windowSize) / windowSize^2; % or just use fspecial
bbox = [742 253 137 56]; % i just picked this box manually
[a,b] = size(bbox);
for i = 1:a
xi = horzcat( bbox( i,1 ), bbox( i,1 ), bbox( i,1) + bbox( i,3 ), bbox( i,1 ) + bbox( i,3 ) );
yi = horzcat( bbox( i,2 ), bbox( i,2 ) + bbox( i,4 ), bbox( i,2 ) + bbox( i,4 ), bbox( i,2 ) );
bw = poly2mask( xi, yi, B(1), B(2));
blurredImage = imfilter(txtimg,kernel,'same');
blurredMask = imfilter(im2double(bw),kernel,'same'); % cast input as double
% composite images by multiplication
txtimg = im2uint8(im2double(blurredImage).*blurredMask + im2double(txtimg).*(1-blurredMask));
end
imshow(txtimg);
The major points:
You were compositing the two images by means of logical indexing. That's fine, but your mask has a single channel, while your image has 3. Consequently, you're only addressing channel 1 (red). This also means that there really isn't much point in blurring the mask, since the indexing can't partially select a pixel.
Similarly, imfilter() will cast the output to match the input class. If you pass it a logical image, it will blur it and then threshold it again . The result is still a hard-edged mask. If you're trying to create a feathered mask, you have to make sure that the input to imfilter is numeric instead of logical.
In order to actually apply this feathered filter, do the compositing by multiplication. Pay attention to image class, as integer types have restrictions. It's easiest to do this in double and then cast back.
Minor points:
Depending on what exactly you want, you may find that a gaussian filter gives better results.
kernel = fspecial('gaussian',[20 20],10); % play with the size, sigma
Using hard-edged filters tends to cause edge-replication artifacts which may tend to be revealing of the original content.
If you really want to get rid of the content, either use a larger filter, or use a different method. Perhaps spatial downsampling would be an option:
txtimg = imread('https://www.mathworks.com/matlabcentral/answers/uploaded_files/874225/image.png');
B = size(txtimg);
windowSize = 20; % doesn't need to be inside loop
kernel = ones(windowSize, windowSize) / windowSize^2; % or just use fspecial
bbox = [742 253 137 56]; % i just picked this box manually
blurredImage = imresize(imresize(txtimg,1/15),B(1:2),'nearest');
[a,b] = size(bbox);
for i = 1:a
xi = horzcat( bbox( i,1 ), bbox( i,1 ), bbox( i,1) + bbox( i,3 ), bbox( i,1 ) + bbox( i,3 ) );
yi = horzcat( bbox( i,2 ), bbox( i,2 ) + bbox( i,4 ), bbox( i,2 ) + bbox( i,4 ), bbox( i,2 ) );
bw = poly2mask( xi, yi, B(1), B(2));
blurredMask = imfilter(im2double(bw),kernel,'same');
txtimg = im2uint8(im2double(blurredImage).*blurredMask + im2double(txtimg).*(1-blurredMask));
end
imshow(txtimg);
Cassandra Adela
Cassandra Adela am 26 Jan. 2022
Johndel Chan
Johndel Chan am 26 Jan. 2022
@DGM Thanks for the help and I really appreciate the explanation you gave for each solution that you provided! The script now works on my end too. Being partly new to image processing, it seems like I have a lot more to learn about it.

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (0)

Community Treasure Hunt

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

Start Hunting!

Translated by