gusucode.com > vision工具箱matlab源码程序 > vision/insertText.m
function RGB = insertText(I, position, text, varargin) %insertText Insert text in image or video stream. % This function inserts text into an image or video. You can use it with % either a grayscale or truecolor image input. % % RGB = insertText(I, position, textString) returns a truecolor image % with text string inserted into it. The input image, I, can be either a % truecolor or grayscale image. position is an M-by-2 matrix of [x y] % coordinates of the upper-left corner of the text bounding box. The input % textString can be a single UNICODE text string or a cell array of % UNICODE strings of length M, where M is the number of rows in position. % If a single text string is provided it is used for all positions. % % RGB = insertText(I, position, numericValue) returns a truecolor image % with numeric values inserted into it. numericValue can be a scalar or a % vector of length M. If a scalar value is provided it is used for all % positions. Numeric values are converted to string using format '%0.5g' % as used by SPRINTF. % % RGB = insertText(..., Name, Value) % specifies additional name-value pair arguments described below: % % 'Font' Font face of text. Specify the font of the text as one % of the available truetype fonts installed on your % system. To get a list of available fonts, type % 'listTrueTypeFonts' in the command prompt. % % Default: 'LucidaSansRegular' % % 'FontSize' Font size, specified in points, as a positive integer % value. Value must be between 1 and 200. % % Default: 12 % % 'TextColor' Color for the text string. You can specify a different % color for each string, or one color for all the strings. % - To specify a color for each text string, set % 'TextColor' to a cell array of M strings or an M-by-3 % matrix of RGB values. % - To specify one color for all text strings, set % 'TextColor' to either a color string or an [R G B] % vector. % RGB values must be in the range of the image data type. % Supported color strings are, 'blue', 'green', 'red', % 'cyan', 'magenta', 'yellow', 'black', 'white' % % Default: 'black' % % 'BoxColor' Color of the text box. Specify the color in the same way % as the 'TextColor'. % % Default: 'yellow' % % 'BoxOpacity' A scalar value from 0 to 1 defining the opacity of the % text box. 0 corresponds to fully transparent and 1 to % fully opaque. No text box appears when BoxOpacity is 0. % % Default: 0.6 % % 'AnchorPoint' Defines the relative location of a point on the text % box. Text box for each text string is positioned by % placing the reference point (called anchor point) of the % text box at point [x y] defined by a row in 'position'. % AnchorPoint can be one of the following strings: % 'LeftTop', 'CenterTop', 'RightTop', % 'LeftCenter', 'Center', 'RightCenter', % 'LeftBottom', 'CenterBottom', 'RightBottom' % % Default: 'LeftTop' % % Note % ---- % For code generation, only ASCII or extended ASCII textString is supported. % % Class Support % ------------- % The class of input I can be uint8, uint16, int16, double, single. Output % RGB matches the class of I. % % Example 1: Insert numeric values and Non-ASCII character % -------------------------------------------------------- % I = imread('peppers.png'); % position = [1 50; 100 50]; % [x y] % value = [555 pi]; % % % Display numeric values % RGB = insertText(I, position, value, 'Font', 'LucidaSansRegular', ... % 'AnchorPoint', 'LeftBottom'); % % Display non-ASCII character (U+014C) % OWithMacron=native2unicode([hex2dec('C5') hex2dec('8C')],'UTF-8'); % RGB = insertText(RGB, [256 50], OWithMacron, 'BoxColor', 'w'); % figure % imshow(RGB) % title('Numeric values and Non-ASCII character') % % Example 2: Insert numbers and strings % ------------------------------------- % I = imread('board.tif'); % % Create texts with fractional values % text_str = cell(3,1); % conf_val = [85.212 98.76 78.342]; % Detection confidence % for ii=1:3 % text_str{ii} = ['Confidence: ' num2str(conf_val(ii),'%0.2f') '%']; % end % position = [23 373; 35 185; 77 107]; % [x y] % box_color = {'red','green','yellow'}; % % RGB = insertText(I, position, text_str, 'FontSize', 18, ... % 'BoxColor', box_color, 'BoxOpacity', 0.4); % figure % imshow(RGB) % title('Board') % % See also insertShape, insertMarker, insertObjectAnnotation, % listTrueTypeFonts %#codegen %#ok<*EMCA> % included shapeWidth, shapeHeight parameter to control text box width % for insertObjectAnnotation %% == Parse inputs and validate == narginchk(3,19); [RGB, position, text, isScalarText, anchorPoint, textColor, boxColor, ... boxOpacity, font, fontFileName, faceIndex, fontSize, ... shapeWidth, shapeHeight, isEmpty] = ... validateAndParseInputs(I, position, text, varargin{:}); % handle empty I or empty position if isEmpty return; end %% == get glyph info == if isSimMode [glyphStruct,fontStruct,maxBitmapSize]= ... populateGlyphBuffer_sim(font,fontFileName,faceIndex,fontSize); else [glyphStruct,fontStruct,maxBitmapSize]= ... populateGlyphBuffer_cg(fontFileName,faceIndex,fontSize); end isNumericText = coder.internal.const(isnumeric(text)); numPos = size(position, 1); textIdx = 1; for ii=1:numPos if (~isScalarText) textIdx = ii; end %thisText = getTextStr(text, textIdx); if (isNumericText) thisTextVal = text(textIdx); thisText = cvstNum2Str(thisTextVal); else thisText = text{textIdx}; end thisTextU16 = uint16(thisText); if (~isempty(thisTextU16)) %% == insert text box == [RGB, textLocationXY, spaceCharWidth] = insertTextBox(RGB, ... position(ii,:), thisTextU16, anchorPoint, ... boxColor(ii,:), boxOpacity, glyphStruct, fontStruct, font, ... shapeWidth(ii), shapeHeight(ii)); %% == Output == if ~isSimMode() RGB = insertGlyphs(RGB, thisTextU16, textLocationXY, ... textColor(ii,:),glyphStruct,fontStruct,spaceCharWidth); else visionInsertGlyph(RGB, thisTextU16, textLocationXY, ... textColor(ii,:),glyphStruct,fontStruct,spaceCharWidth, ... maxBitmapSize); end end end %========================================================================== % Parse inputs and validate for simulation %========================================================================== function [RGB,position,outText,isScalarText,anchorPoint,textColor,... boxColor,boxOpacity,font,fontFileName,faceIndex, ... fontSize,shapeWidth,shapeHeight,isEmpty] = ... validateAndParseInputs(I, position, text, varargin) coder.extrinsic('listTrueTypeFonts'); %--input image-- checkImage(I); RGB = convert2RGB(I); inpClass = class(I); %--position-- % position data type does not depend on input data type validateattributes(position, {'numeric'}, ... {'real','nonsparse', '2d', 'finite', 'size', [NaN 2]}, ... mfilename,'POSITION', 2); position = int32(position); numPos = size(position, 1); %--text-- checkText(text); % text conversion: [numTexts, outText] = getTexts(text); %--isEmpty-- isEmpty = isempty(I) || isempty(position); %--other optional parameters-- if isSimMode() [anchorPoint, textColor, boxColor, boxOpacity, ... font, fontSize, shapeWidth, shapeHeight] = ... validateAndParseOptInputs_sim(inpClass,varargin{:}); else [anchorPoint, textColor, boxColor, boxOpacity, ... font, fontSize, shapeWidth, shapeHeight] = ... validateAndParseOptInputs_cg(inpClass,varargin{:}); end crossCheckInputs(position, numTexts, textColor, boxColor); textColor = getColorMatrix(inpClass, numPos, textColor); boxColor = getColorMatrix(inpClass, numPos, boxColor); shapeWidth = getShapeDimMatrix(shapeWidth, numPos); shapeHeight = getShapeDimMatrix(shapeHeight, numPos); if isSimMode() [fontFileName, faceIndex] = getFontFilenameFaceindex_sim(font); else [fontFileName, faceIndex] = coder.internal.const( ... getFontFilenameFaceindex_cg(coder.internal.const(font))); end % check that fontFileName is not empty errIf0(isempty(fontFileName), 'vision:insertText:FontFileMissing'); isScalarText = (numTexts==1); %========================================================================== function [anchorPoint,textColor,boxColor,boxOpacity, ... font,fontSize, shapeWidth, shapeHeight] = ... validateAndParseOptInputs_sim(inpClass,varargin) % Validate and parse optional inputs persistent parser persistent oldInpClass if isempty(parser)||isempty(oldInpClass)||(~strcmp(oldInpClass, inpClass)) defaults = getDefaultParameters(inpClass); % Setup parser parser = inputParser; parser.CaseSensitive = false; parser.FunctionName = mfilename; parser.addParameter('AnchorPoint', defaults.AnchorPoint); parser.addParameter('TextColor', defaults.TextColor); parser.addParameter('BoxColor', defaults.BoxColor); parser.addParameter('BoxOpacity', defaults.BoxOpacity, ... @checkBoxOpacity); parser.addParameter('Font', defaults.Font); parser.addParameter('FontSize', defaults.FontSize, @checkFontSize); parser.addParameter('ShapeWidth',defaults.ShapeWidth,@checkShapeWidth); parser.addParameter('ShapeHeight',defaults.ShapeHeight,@checkShapeHeight); oldInpClass = inpClass; end %Parse input parser.parse(varargin{:}); anchorPoint = checkAnchorPoint(parser.Results.AnchorPoint); textColor = checkColor(parser.Results.TextColor, 'TextColor'); boxColor = checkColor(parser.Results.BoxColor, 'BoxColor'); boxOpacity = double(parser.Results.BoxOpacity); font = checkFont(parser.Results.Font);% readjusted case in font name fontSize = int32(parser.Results.FontSize); shapeWidth = int32(parser.Results.ShapeWidth); shapeHeight = int32(parser.Results.ShapeHeight); %========================================================================== function [anchorPoint,textColor,boxColor,boxOpacity, ... font,fontSize, shapeWidth, shapeHeight] = ... validateAndParseOptInputs_cg(inpClass,varargin) % Validate and parse optional inputs defaultsNoVal = getDefaultParametersNoVal(); defaults = getDefaultParameters(inpClass); properties = getEmlParserProperties(); optarg = eml_parse_parameter_inputs(defaultsNoVal,properties,varargin{:}); anchorPoint = (eml_get_parameter_value(optarg.AnchorPoint, ... defaults.AnchorPoint, varargin{:})); textColor = (eml_get_parameter_value(optarg.TextColor, ... defaults.TextColor, varargin{:})); boxColor = (eml_get_parameter_value(optarg.BoxColor, ... defaults.BoxColor, varargin{:})); boxOpacity = (eml_get_parameter_value(optarg.BoxOpacity, ... defaults.BoxOpacity, varargin{:})); font = (eml_get_parameter_value(optarg.Font, ... defaults.Font, varargin{:})); fontSize = (eml_get_parameter_value(optarg.FontSize, ... defaults.FontSize, varargin{:})); shapeWidth = (eml_get_parameter_value(optarg.ShapeWidth, ... defaults.ShapeWidth, varargin{:})); shapeHeight = (eml_get_parameter_value(optarg.ShapeHeight, ... defaults.ShapeHeight, varargin{:})); anchorPoint = coder.internal.const(checkAnchorPoint(anchorPoint)); textColor = checkColor(textColor, 'TextColor'); boxColor = checkColor(boxColor, 'BoxColor'); checkBoxOpacity(boxOpacity); boxOpacity = double(boxOpacity); % FontSize must be a constant if (nargin>1) && (optarg.FontSize ~= uint32(0)) % FontSize is user-defined here eml_invariant(eml_is_const(fontSize), ... eml_message('vision:insertText:FontSizeNonConst')); end font = coder.internal.const(checkFont(font));% readjusted case checkFontSize(fontSize); fontSize = coder.internal.const(int32(fontSize)); % shapeWidth, shapeHeight for internal use only; skipping checks in codegen %========================================================================== function checkImage(I) % Validate input image validateattributes(I,{'uint8', 'uint16', 'int16', 'double', 'single'}, ... {'real','nonsparse'}, mfilename, 'I', 1) % input image must be 2d or 3d (with 3 planes) errIf0((ndims(I) > 3) || ((size(I,3) ~= 1) && (size(I,3) ~= 3)), ... 'vision:dims:imageNot2DorRGB'); %========================================================================== function checkText(text) % Validate text if isnumeric(text) validateattributes(text, {'numeric'}, ... {'real', 'nonsparse', 'nonnan', 'finite', 'nonempty', 'vector'}, ... mfilename, 'TEXT'); else if ischar(text) validateattributes(text,{'char'},{},mfilename, 'TEXT'); textCell = {text}; else validateattributes(text,{'cell'}, {'nonempty', 'vector'}, ... mfilename, 'TEXT'); for i=1:length(text) errIf0(~ischar(text{i}), 'vision:insertText:textCellNonChar'); end textCell = text; end % Following escape characters are not supported % \b Backspace % \f Form feed % \r Carriage return % \t Horizontal tab % \n line termination : supported by insertText, % but not by insertObjectAnnotation if isSimMode() throwErrorForEscapeChar_sim(textCell, {'\b','\f','\r','\t'}); else throwErrorForEscapeChar_cg(textCell); end end %========================================================================== function throwErrorForEscapeChar_sim(textCell, escapeCharsCell) for ii=1:length(escapeCharsCell) escapeChar = sprintf(escapeCharsCell{ii}); escapeCharIdx = strfind(textCell, escapeChar); hasEscapeChar = ~isempty([escapeCharIdx{1:end}]); errIf1(hasEscapeChar, 'vision:insertText:unsupportedEscapeChar', ... escapeCharsCell{ii}); end %========================================================================== % function thisText = getTextStr(txt, textIdx) % isNumericText = coder.internal.const(isnumeric(txt)); % if (isNumericText) % thisTextVal = txt(textIdx); % thisText = cvstNum2Str(thisTextVal); % else % thisText = txt{textIdx}; % end %========================================================================== function throwErrorForEscapeChar_cg(textCell) % This function is used only if input text is Non-numeric for i=1:length(textCell) txtTmp = uint16(textCell{i}); % Escape characters: {'\b','\f','\r','\t'} escapeCharU16_b = uint16(8); % uint16(sprintf('\b')) hasEscapeChar_b = ~isempty(find(txtTmp == escapeCharU16_b, 1)); errIf1(hasEscapeChar_b,'vision:insertText:unsupportedEscapeChar','\b'); escapeCharU16_f = uint16(12); % uint16(sprintf('\f')) hasEscapeChar_f = ~isempty(find(txtTmp == escapeCharU16_f, 1)); errIf1(hasEscapeChar_f,'vision:insertText:unsupportedEscapeChar','\f'); escapeCharU16_r = uint16(13); % uint16(sprintf('\r')) hasEscapeChar_r = ~isempty(find(txtTmp == escapeCharU16_r, 1)); errIf1(hasEscapeChar_r,'vision:insertText:unsupportedEscapeChar','\r'); escapeCharU16_t = uint16(9); % uint16(sprintf('\t')) hasEscapeChar_t = ~isempty(find(txtTmp == escapeCharU16_t, 1)); errIf1(hasEscapeChar_t,'vision:insertText:unsupportedEscapeChar','\t'); end %========================================================================== function anchorPointOut = checkAnchorPoint(anchorPoint) % Validate AnchorPoint anchorPointOut = coder.internal.const(validatestring(anchorPoint, ... {'LeftTop', 'LeftCenter', 'LeftBottom', ... 'RightTop', 'RightCenter', 'RightBottom', ... 'CenterTop', 'CenterCenter', 'Center', 'CenterBottom'}, ... mfilename,'AnchorPoint')); %========================================================================== function crossCheckInputs(position, numTexts, textColor, boxColor) % Cross validate inputs numRowsPositions = size(position, 1); numBoxColor = getNumColors(boxColor); numTextColors = getNumColors(textColor); % cross check text and position (rows) errIf0((numTexts ~=1) && (numTexts ~= numRowsPositions), ... 'vision:insertText:invalidNumTexts'); % cross check color and position (rows). Empty color is caught here errIf0((numBoxColor ~= 1) && (numRowsPositions ~= numBoxColor), ... 'vision:insertText:invalidNumPosNumBoxColor'); % cross check text color and position (rows). Empty color is caught here errIf0((numTextColors ~= 1) && (numRowsPositions ~= numTextColors), ... 'vision:insertText:invalidNumPosNumTextColor'); %========================================================================== function colorOut = getColorMatrix(inpClass, numPos, color) colorRGB = colorRGBValue(color, inpClass); if (size(colorRGB, 1)==1) colorOut = repmat(colorRGB, [numPos 1]); else colorOut = colorRGB; end %========================================================================== function shapeDimOut = getShapeDimMatrix(shapeDim, numPos) if length(shapeDim)==1 shapeDimOut = repmat(shapeDim, [numPos 1]); else shapeDimOut = shapeDim; end %========================================================================== function numColors = getNumColors(color) % Get number of colors numColors = 1; if isnumeric(color) numColors = size(color,1); elseif iscell(color) % if color='red', it is converted to cell earlier numColors = length(color); end %========================================================================== function flag = isDefaultFont(font) % called only in sim mode flag = false; if strcmp(getDefaultFont_sim(), font) flag = true; end %========================================================================== function defaultFont = getDefaultFont_sim() persistent origDefFont if isempty(origDefFont) origDefFont = vision.internal.getDefaultFont(); end defaultFont = origDefFont; %========================================================================== function defaultFont = getDefaultFont_cg() coder.extrinsic('vision.internal.getDefaultFont'); defaultFont = coder.internal.const(vision.internal.getDefaultFont()); %========================================================================== function defaults = getDefaultParameters(inpClass) % Get default values for optional parameters % default color 'black', default text color 'yellow' if isSimMode() origDefFont = getDefaultFont_sim(); else origDefFont = getDefaultFont_cg(); end black = [0 0 0]; switch inpClass case {'double', 'single'} yellow = [1 1 0]; case 'uint8' yellow = [255 255 0]; case 'uint16' yellow = [65535 65535 0]; case 'int16' yellow = [32767 32767 -32768]; black = [-32768 -32768 -32768]; end defFont = coder.internal.const(origDefFont); defaults = struct(... 'AnchorPoint', 'LeftTop', ... 'TextColor', black, ... 'BoxColor', yellow, ... 'BoxOpacity', 0.6,... 'Font', defFont, ... 'FontSize', 12, ... 'ShapeWidth', 0, ... 'ShapeHeight', 0); %========================================================================== function defaults = getDefaultParametersNoVal() defaults = struct(... 'AnchorPoint', uint32(0), ... 'TextColor', uint32(0), ... 'BoxColor', uint32(0), ... 'BoxOpacity', uint32(0),... 'Font', uint32(0), ... 'FontSize', uint32(0), ... 'ShapeWidth', uint32(0), ... 'ShapeHeight', uint32(0)); %========================================================================== function properties = getEmlParserProperties() properties = struct( ... 'CaseSensitivity', false, ... 'StructExpand', true, ... 'PartialMatching', false); %========================================================================== function colorOut = checkColor(color, paramName) % Validate 'BoxColor' or 'TextColor' % Validate color if isnumeric(color) % must have 6 columns validateattributes(color, ... {'uint8','uint16','int16','double','single'},... {'real','nonsparse','nonnan', 'finite', '2d', 'size', [NaN 3]}, ... mfilename, paramName); colorOut = color; else if ~isSimMode() % codegen does not support cell array errIf0(~isnumeric(color), 'vision:insertShape:colorNotNumeric'); colorOut = color; else if ischar(color) colorCell = {color}; else validateattributes(color, {'cell'}, {}, mfilename, 'BoxColor'); colorCell = color; end supportedColorStr = {'blue','green','red','cyan','magenta', ... 'yellow','black','white'}; numCells = length(colorCell); colorOut = cell(1, numCells); for ii=1:numCells colorOut{ii} = validatestring(colorCell{ii}, ... supportedColorStr, mfilename, paramName); end end end %========================================================================== function fontOut = checkFont(font) % Validate 'Font'. Do a case insensitive match coder.extrinsic('vision.internal.getFontNamesInCell'); fontOut = coder.internal.const(validatestring(coder.internal.const(font), ... coder.internal.const(vision.internal.getFontNamesInCell()), ... mfilename,'Font')); %========================================================================== function tf = checkBoxOpacity(opacity) % Validate 'BoxOpacity' validateattributes(opacity, {'numeric'}, {'nonempty', 'nonnan', ... 'finite', 'nonsparse', 'real', 'scalar', '>=', 0, '<=', 1}, ... mfilename, 'BoxOpacity'); tf = true; %========================================================================== function tf = checkFontSize(FontSize) % Validate 'FontSize' % Maximum font size in MS Word is 1638 validateattributes(FontSize, {'numeric'}, ... {'nonempty', 'integer', 'nonsparse', 'scalar', '>', 0, '<=', 200}, ... mfilename, 'FontSize'); tf = true; %========================================================================== function tf = checkShapeWidth(ShapeWidth) % Validate 'ShapeWidth' validateattributes(ShapeWidth, {'numeric'}, ... {'nonempty', 'integer', 'nonsparse', '>=', 0}, ... mfilename, 'ShapeWidth'); tf = true; %========================================================================== function tf = checkShapeHeight(ShapeHeight) % Validate 'ShapeHeight' validateattributes(ShapeHeight, {'numeric'}, ... {'nonempty', 'integer', 'nonsparse', '>=', 0}, ... mfilename, 'ShapeHeight'); tf = true; %========================================================================== function inRGB = convert2RGB(I) if ismatrix(I) inRGB = cat(3, I , I, I); else inRGB = I; end %========================================================================== function outColor = colorRGBValue(inColor, inpClass) if isnumeric(inColor) outColor = cast(inColor, inpClass); else if iscell(inColor) textColorCell = inColor; else textColorCell = {inColor}; end numColors = length(textColorCell); outColor = zeros(numColors, 3, inpClass); for ii=1:numColors supportedColorStr = {'blue','green','red','cyan','magenta','yellow',... 'black','white'}; % http://www.mathworks.com/help/techdoc/ref/colorspec.html colorValuesFloat = [0 0 1;0 1 0;1 0 0;0 1 1;1 0 1;1 1 0;0 0 0;1 1 1]; idx = strcmp(textColorCell{ii}, supportedColorStr); switch inpClass case {'double', 'single'} outColor(ii, :) = colorValuesFloat(idx, :); case {'uint8', 'uint16'} colorValuesUint = colorValuesFloat*double(intmax(inpClass)); outColor(ii, :) = colorValuesUint(idx, :); case 'int16' colorValuesInt16 = im2int16(colorValuesFloat); outColor(ii, :) = colorValuesInt16(idx, :); end end end %========================================================================== function [numTexts, textOut] = getTexts(textIn) if isnumeric(textIn) numTexts = length(textIn); textOut = textIn; % scalar or vector else if ischar(textIn) numTexts = 1; textOut = {textIn}; else % must be cell numTexts = length(textIn); textOut = textIn; end end %========================================================================== function [glyphStruct, fontStruct, maxBitmapSize] = ... splitInfoStruct(infoStruct) glyphStruct.glyphBitmapArray = infoStruct.glyphBitmapArray; glyphStruct.glyphIdxFromCharcode = infoStruct.glyphIdxFromCharcode; glyphStruct.glyphBitmapStartIdx = infoStruct.glyphBitmapStartIdx; glyphStruct.glyphWidths = infoStruct.glyphWidths; glyphStruct.glyphHeights = infoStruct.glyphHeights; glyphStruct.glyphXAdvances = infoStruct.glyphXAdvances; glyphStruct.glyphLeftBearings = infoStruct.glyphLeftBearings; glyphStruct.glyphTopBearings = infoStruct.glyphTopBearings; % fontStruct.fontAscend = infoStruct.fontAscend; fontStruct.fontDescend = infoStruct.fontDescend; fontStruct.fontLinespace = infoStruct.fontLinespace; maxBitmapSize = infoStruct.maxBitmapSize; %========================================================================== function infoStruct = populateInfoStruct_sim(fontFileName,... faceIndex,fontSize) [glyphBitmapArray, ... glyphIdxFromCharcode, ... glyphBitmapStartIdx, ... glyphWidths, ... glyphHeights, ... glyphXAdvances, ... glyphLeftBearings, ... glyphTopBearings, ... fontAscend, ... fontDescend, ... fontLinespace, ... maxBitmapSize]=visionPopulateGlyphBuffer(fontFileName,faceIndex, ... fontSize,false); infoStruct.glyphBitmapArray = glyphBitmapArray; infoStruct.glyphIdxFromCharcode = glyphIdxFromCharcode; infoStruct.glyphBitmapStartIdx = glyphBitmapStartIdx; infoStruct.glyphWidths = glyphWidths; infoStruct.glyphHeights = glyphHeights; infoStruct.glyphXAdvances = glyphXAdvances; infoStruct.glyphLeftBearings = glyphLeftBearings; infoStruct.glyphTopBearings = glyphTopBearings; % infoStruct.fontAscend = fontAscend; infoStruct.fontDescend = fontDescend; infoStruct.fontLinespace = fontLinespace; infoStruct.maxBitmapSize = maxBitmapSize; %========================================================================== function [glyphStruct, fontStruct, maxBitmapSize] = ... populateGlyphBuffer_sim(font,fontFileName, faceIndex, fontSize) persistent fontHashTable persistent infoStructArray if isempty(fontHashTable) fontHashTable = containers.Map('KeyType', 'char', 'ValueType', 'uint16'); end if isempty(infoStructArray) infoStructArray = []; end % create unique key from font name and font size fontLower = lower(font); thisKey = [fontLower num2str(fontSize)]; if isKey(fontHashTable, thisKey) % retrieve glyph and font info from table thisValue = fontHashTable(thisKey); infoStruct = infoStructArray(thisValue); else try %#ok<EMTC> % populate infoStruct and append it to infoStructArray only at success infoStruct = populateInfoStruct_sim(fontFileName,faceIndex, fontSize); catch ME throw(ME); end % add the new key and the corresponding value. % the values are [1,2,3...] thisValue = uint16(fontHashTable.Count+1); fontHashTable(thisKey) = thisValue; infoStructArray = [infoStructArray infoStruct]; % here infoStructArray(thisValue) is the infoStruct corresponding to % thisKey end [glyphStruct, fontStruct, maxBitmapSize] = splitInfoStruct(infoStruct); %========================================================================== function [fontFileName, faceIndex] = getFontFilenameFaceindex_cg(font) coder.extrinsic('listTrueTypeFonts'); oldFontFNameFIdx = coder.internal.const( ... listTrueTypeFonts(coder.internal.const(font))); fontFileName = coder.internal.const(oldFontFNameFIdx.fileName); faceIndex = coder.internal.const(oldFontFNameFIdx.faceIndex); %========================================================================== function [fontFileName, faceIndex] = getFontFilenameFaceindex_sim(font) persistent oldFont persistent oldFontFileName persistent oldFaceIndex if isempty(oldFontFileName) || ~strcmp(oldFont, font) oldFontFNameFIdx = coder.internal.const( ... listTrueTypeFonts(coder.internal.const(font))); oldFontFileName = oldFontFNameFIdx.fileName; oldFaceIndex = oldFontFNameFIdx.faceIndex; end oldFont = font; fontFileName = coder.internal.const(oldFontFileName); faceIndex = coder.internal.const(oldFaceIndex); %========================================================================== function [glyphStruct, fontStruct, maxBitmapSize] = ... populateGlyphBuffer_cg(fontFileName, faceIndex, fontSize) coder.extrinsic('visionPopulateGlyphBuffer'); % call built-in function [glyphBitmapArray, ... glyphIdxFromCharcode, ... glyphBitmapStartIdx, ... glyphWidths, ... glyphHeights, ... glyphXAdvances, ... glyphLeftBearings, ... glyphTopBearings, ... fontAscend, ... fontDescend, ... fontLinespace, ... maxBitmapSize] = coder.internal.const(... visionPopulateGlyphBuffer(fontFileName, faceIndex, fontSize, true)); glyphStruct.glyphBitmapArray = glyphBitmapArray; glyphStruct.glyphIdxFromCharcode = glyphIdxFromCharcode; glyphStruct.glyphBitmapStartIdx = glyphBitmapStartIdx; glyphStruct.glyphWidths = glyphWidths; glyphStruct.glyphHeights = glyphHeights; glyphStruct.glyphXAdvances = glyphXAdvances; glyphStruct.glyphLeftBearings = glyphLeftBearings; glyphStruct.glyphTopBearings = glyphTopBearings; % fontStruct.fontAscend = fontAscend; fontStruct.fontDescend = fontDescend; fontStruct.fontLinespace = fontLinespace; %========================================================================== function [tbWidth, tbHeight, spaceCharWidth] = ... getTextboxWidthHeight(ucTextU16, glyphIdxFromCharcode, ... glyphXAdvances, fontStruct, font, shapeWidth) % New line character does not have any width; It just contributes to height % So, for width computation, we don't consider NewLineCharacter. % That means: for five new line character and no text: % text box height is non-zero, but width is zero, so no text box is drawn % % So, for height computation, we DO consider NewLineCharacter. That means: % for each new line character, we increase the height fontHeightWLinegap = fontStruct.fontLinespace; fontHeightWOLinegap = fontStruct.fontAscend - fontStruct.fontDescend; %fontLinegap = fontHeightWLinegap - fontHeightWOLinegap; ucNewlineCarcode = uint16(10); idxNewlineChar = find(ucTextU16==ucNewlineCarcode); numLines = length(idxNewlineChar)+1; tbHeight = int32(fontHeightWOLinegap + fontHeightWLinegap*(numLines-1)); b1 = 1; % for converting 0-based to 1-based spaceCharWidth = getSpaceCharWidth(glyphIdxFromCharcode, ... glyphXAdvances, fontHeightWOLinegap); if isempty(idxNewlineChar) thisCharcodes_1b = ucTextU16+b1; thisGlyphIdxs = glyphIdxFromCharcode(thisCharcodes_1b); thisGlyphIdxs_1b = thisGlyphIdxs + b1; tbWidth = int32(sum(glyphXAdvances(thisGlyphIdxs_1b))); % glyph index 0 means no glyph found numMissingGlyph =sum(uint32(glyphIdxFromCharcode(thisCharcodes_1b))==0); hasMissingCharInFont = (numMissingGlyph ~= 0); tbWidth = int32(tbWidth + int32(numMissingGlyph*spaceCharWidth)); else %first segment firstSegment = ucTextU16(1:(idxNewlineChar(1)-1)); thisCharcodes_1b = firstSegment+b1; thisGlyphIdxs = glyphIdxFromCharcode(thisCharcodes_1b); thisGlyphIdxs_1b = thisGlyphIdxs + b1; lenFirstSegment = sum(glyphXAdvances(thisGlyphIdxs_1b)); % for character code with no glyph, we replace that by space; account % for space width numMissingGlyph=sum(uint32(glyphIdxFromCharcode(thisCharcodes_1b))==0); hasMissingCharInFont = (numMissingGlyph ~= 0); lenFirstSegment = lenFirstSegment + numMissingGlyph*spaceCharWidth; maxLen = int32(0); for i=2:(length(idxNewlineChar)-1) startIdx = idxNewlineChar(i)+1; endIdx = idxNewlineChar(i+1)-1; thisSegment = ucTextU16(startIdx:endIdx); thisCharcodes_1b = thisSegment+b1; thisGlyphIdxs = glyphIdxFromCharcode(thisCharcodes_1b); thisGlyphIdxs_1b = thisGlyphIdxs + b1; lenThisSegment = sum(glyphXAdvances(thisGlyphIdxs_1b)); numMissingGlyph=sum(uint32(glyphIdxFromCharcode(thisCharcodes_1b))==0); hasMissingCharInFont = hasMissingCharInFont||(numMissingGlyph ~= 0); lenThisSegment = lenThisSegment + numMissingGlyph*spaceCharWidth; if lenThisSegment > maxLen maxLen(:) = lenThisSegment; end end endSegment = ucTextU16((idxNewlineChar(end)+1):end); thisCharcodes_1b = endSegment+b1; thisGlyphIdxs = glyphIdxFromCharcode(thisCharcodes_1b); thisGlyphIdxs_1b = thisGlyphIdxs + b1; lenEndSegment = sum(glyphXAdvances(thisGlyphIdxs_1b)); numMissingGlyph=sum(uint32(glyphIdxFromCharcode(thisCharcodes_1b))==0); hasMissingCharInFont = hasMissingCharInFont || (numMissingGlyph ~= 0); lenEndSegment = lenEndSegment + numMissingGlyph*spaceCharWidth; maxLen = max([lenFirstSegment maxLen lenEndSegment]); tbWidth = int32(maxLen); end % Adjust tbWidth if smaller than shapeWidth for insertObjectAnnotation tbWidth = max(tbWidth, shapeWidth); if isSimMode if (hasMissingCharInFont) if isDefaultFont(font) warning(message('vision:insertText:missingCharInDefFont', font)); else warning(message('vision:insertText:missingCharInFont', font)); end end end %========================================================================== % overlap condition: function hasOverlap = shapeAndImageHasOverlaps(bbox_x1, bbox_y1, ... shapeWidth, shapeHeight, imageWidth, imageHeight) % returns true even if there is at least 1 pixel overlap bbox_x2 = bbox_x1 + shapeWidth-1; bbox_y2 = bbox_y1 + shapeHeight-1; hasOverlap = (bbox_x1 <= imageWidth && bbox_x2 >= 1 && ... bbox_y1 <= imageHeight && bbox_y2 >= 1); %========================================================================== function [tbTopLeftX, tbTopLeftY] = getTextboxTopLeftPosition( ... tbLocationXY, tbWidth, tbHeight, anchorPoint, shapeWidth, ... shapeHeight, imageWidth, imageHeight) tbLocationX = tbLocationXY(1); tbLocationY = tbLocationXY(2); switch lower(anchorPoint) case 'lefttop' tbTopLeftY = tbLocationY; tbTopLeftX = tbLocationX; case 'leftcenter' tbTopLeftY = tbLocationY-int32(tbHeight/2); tbTopLeftX = tbLocationX; case 'leftbottom' tbTopLeftY = tbLocationY-int32(tbHeight)+1; tbTopLeftX = tbLocationX; if (shapeWidth>0) && (shapeHeight>0) % make sure at least 1 pixel in bounding box is inside image hasOverlap = shapeAndImageHasOverlaps(tbTopLeftX, ... tbTopLeftY+tbHeight, shapeWidth, shapeHeight, ... imageWidth, imageHeight); if hasOverlap % top border if tbTopLeftY<1 % row % top of textBoxBorder outside image top border if ((tbTopLeftY + tbHeight + shapeHeight)>=1) % bounding boxes bottom border is inside image's % top border tbTopLeftY = tbLocationY + shapeHeight +1; % row end end % right border bboxLeftBorder = tbTopLeftX; % in next line we will readjust textBoxLeftBorder. So we % need to save the original bboxLeftBorder in above line textBoxRightBorder = tbTopLeftX + tbWidth; % col adjBorder = textBoxRightBorder - imageWidth; if adjBorder > 0 % col % right of textBoxBorder outside image right border if tbTopLeftX <= imageWidth % col % bounding boxes left border is inside image's % right border tbTopLeftX = tbTopLeftX - adjBorder + 1; % col % else % tbTopLeftY = imageW + 100; % put textbox's % top border far away so that it is not drawn end end % left border if tbTopLeftX < 1 % col % left of textBoxBorder outside image left border if bboxLeftBorder + shapeWidth >= 1 % col % bounding boxes right border is inside image's % left border tbTopLeftX = int32(1); % col % else % tbTopLeftY = -(textBoxWidth + 100);%put % textbox's left border far away so that it is % not drawn end end else tbTopLeftY = int32(-32767);%far away tbTopLeftX = int32(-32767);%far away end end case 'righttop' tbTopLeftY = tbLocationY; tbTopLeftX = tbLocationX-int32(tbWidth)+1; case 'rightcenter' tbTopLeftY = tbLocationY-int32(tbHeight/2); tbTopLeftX = tbLocationX-int32(tbWidth)+1; case 'rightbottom' tbTopLeftY = tbLocationY-int32(tbHeight)+1; tbTopLeftX = tbLocationX-int32(tbWidth)+1; case 'centertop' tbTopLeftY = tbLocationY; tbTopLeftX = tbLocationX-int32(tbWidth/2); case 'center' tbTopLeftY = tbLocationY-int32(tbHeight/2); tbTopLeftX = tbLocationX-int32(tbWidth/2); case 'centerbottom' tbTopLeftY = tbLocationY-int32(tbHeight)+1; tbTopLeftX = tbLocationX-int32(tbWidth/2); end %========================================================================== function RGB = insertTextBoxCore(imgIn, tbTopLeftX, tbTopLeftY, ... tbWidth, tbHeight, boxColor, boxOpacity) RGB = imgIn; imSize = int32(size(RGB)); numRowsIm = imSize(1); numColsIm = imSize(2); numPLanes = imSize(3); oneI32 = int32(1); startR = tbTopLeftY; endR = tbTopLeftY+int32(tbHeight)-oneI32; startC = tbTopLeftX; endC = tbTopLeftX+int32(tbWidth)-oneI32; noOverlap = (startR>numRowsIm) || (endR<oneI32) || ... (startC>numColsIm) || (endC<oneI32); if (~noOverlap) if (startR<oneI32) startR = oneI32; end if (endR>numRowsIm) endR = numRowsIm; end if (startC<oneI32) startC = oneI32; end if (endC>numColsIm) endC = numColsIm; end if (boxOpacity>=1) % boxOpacity>1 is caught in arg check for i=1:numPLanes RGB(startR:endR, startC:endC, i) = boxColor(i); end else for i=1:numPLanes RGB(startR:endR, startC:endC, i) = boxOpacity*boxColor(i) + ... (1-boxOpacity)*RGB(startR:endR, startC:endC, i); end end end %========================================================================== function [RGB, textLocationXY, spaceCharWidth] = insertTextBox(RGB, ... position, ucTextU16, ... anchorPoint, boxColor, boxOpacity, ... glyphStruct, fontStruct, font, ... shapeWidth, shapeHeight) % Step-1: get compact textbox width and height % position is an M-by-2 matrix of [x y] coordinates of the upper-left % corner of the text bounding box. [tbWidth, tbHeight, spaceCharWidth] = getTextboxWidthHeight(ucTextU16, ... glyphStruct.glyphIdxFromCharcode,glyphStruct.glyphXAdvances, ... fontStruct, font, shapeWidth); % Step-2: add margin to textbox width and height MARGIN_LeftOrRight = spaceCharWidth; % used 3 before MARGIN_TopOrBottom = spaceCharWidth; % used 3 before % only add left/right margin if the text extends past the shapeWidth if tbWidth>shapeWidth tbWidth = tbWidth + 2*MARGIN_LeftOrRight; end tbHeight = tbHeight + 2*MARGIN_TopOrBottom; % Step-3: Consider anchor point and get text box top-left corner position tbLocationXY = position; imageWidth = size(RGB,2); imageHeight = size(RGB,1); [tbTopLeftX, tbTopLeftY] = getTextboxTopLeftPosition(tbLocationXY, ... tbWidth, tbHeight, anchorPoint, shapeWidth, shapeHeight, ... imageWidth, imageHeight); % % Step-3a: Shift left appropriate amount, if needed. If tbTopLeftX + % % tbWidth is larger than RGB dimensions, shift tbTopLeftX % if tbTopLeftX + tbWidth > size(RGB, 2) % % Calculate excess width beyond image width % excessWidth = tbTopLeftX + tbWidth - size(RGB, 2); % if excessWidth > tbTopLeftX % tbTopLeftX = 0; % else % tbTopLeftX = tbTopLeftX - excessWidth; % end % end % Step-4: get outputs RGB = insertTextBoxCore(RGB, tbTopLeftX, tbTopLeftY, ... tbWidth, tbHeight, boxColor, boxOpacity); textLocationXY.x = tbTopLeftX + int32(MARGIN_LeftOrRight); textLocationXY.y = tbTopLeftY + int32(MARGIN_TopOrBottom); %========================================================================== function imgOut = insertGlyphs(imgIn, ucTextU16, ... textLocationXY, textColor, ... glyphStruct, fontStruct, spaceCharWidth) imSize = int32(size(imgIn)); imgOut = imgIn; numRowsIm = imSize(1); numColsIm = imSize(2); oneI32 = int32(1); numChars = length(ucTextU16); b1 = 1; % to convert to 1 based indexing fontHeightWLinegap = fontStruct.fontLinespace; penX = int32(textLocationXY.x); % go to reference baseline (near the middle of the glyph) penY = int32(textLocationXY.y) + fontStruct.fontAscend; isNewLineChar = (ucTextU16 == uint16(10)); for i=1:numChars %see logic in mdlOutputs of sviptextrender.cpp if isNewLineChar(i) % go to next line penY = penY + fontHeightWLinegap; % reset x position to the beginning on a line penX = textLocationXY.x; else thisCharcode = ucTextU16(i); thisCharcode_1b = thisCharcode+b1; thisGlyphIdx = glyphStruct.glyphIdxFromCharcode(thisCharcode_1b); thisGlyphIdx_1b = thisGlyphIdx + b1; glyphExists = (thisGlyphIdx ~= 0); if ~glyphExists penX = penX + int32(spaceCharWidth); else thisGlyphW = glyphStruct.glyphWidths(thisGlyphIdx_1b); thisGlyphH = glyphStruct.glyphHeights(thisGlyphIdx_1b); xx=penX+int32(glyphStruct.glyphLeftBearings(thisGlyphIdx_1b)); yy=penY-int32(glyphStruct.glyphTopBearings(thisGlyphIdx_1b)); startR_im = yy; endR_im = yy+int32(thisGlyphH)- oneI32; startC_im = xx; endC_im = xx+int32(thisGlyphW)- oneI32; % take care of clipping for out of bound image noOverlap = (startR_im>numRowsIm) || (endR_im<oneI32) || ... (startC_im>numColsIm) || (endC_im<oneI32); if (~noOverlap) % if no overlap, skip this glyph startR_gl = oneI32; startC_gl = oneI32; endR_gl = int32(thisGlyphH); endC_gl = int32(thisGlyphW); if (startR_im<1) startR_gl = -startR_im+int32(2); startR_im = oneI32; end if (endR_im>numRowsIm) endR_gl = int32(thisGlyphH) - (endR_im - numRowsIm); endR_im = numRowsIm; end if (startC_im<1) startC_gl = -startC_im+int32(2); startC_im = oneI32; end if (endC_im>numColsIm) endC_gl = int32(thisGlyphW) - (endC_im - numColsIm); endC_im = numColsIm; end imgIdx.startR_im = startR_im; imgIdx.startC_im = startC_im; imgIdx.endR_im = endR_im; imgIdx.endC_im = endC_im; glIdx.startR_gl = startR_gl; glIdx.startC_gl = startC_gl; glIdx.endR_gl = endR_gl; glIdx.endC_gl = endC_gl; bitmapStartIdx_1b = ... glyphStruct.glyphBitmapStartIdx(thisGlyphIdx_1b) + b1; bitmapEndIdx_1b = bitmapStartIdx_1b + ... uint32(thisGlyphW*thisGlyphH) - uint32(1); thisGlyphBitmap = glyphStruct.glyphBitmapArray(... bitmapStartIdx_1b:bitmapEndIdx_1b); thisGlyphBitmap = ... reshape(thisGlyphBitmap,[thisGlyphW thisGlyphH]); thisGlyphBitmap = thisGlyphBitmap'; % antialiasing if isfloat(imgOut) % text color is double/single([0 1]) range; % no need to convert it imgOut = doGlyph_float(imgOut, thisGlyphBitmap, ... imgIdx, glIdx, textColor); elseif isa(imgOut,'uint8') % text color is uint8([0 255]) range; % no need to convert it imgOut = doGlyph_uint8(imgOut, thisGlyphBitmap, ... imgIdx, glIdx, textColor); elseif isa(imgOut,'uint16') % text color is uint16([0 65535]) range; % no need to convert it imgOut = doGlyph_uint16(imgOut, thisGlyphBitmap, ... imgIdx, glIdx, textColor); elseif isa(imgOut,'int16') imgOut = doGlyph_int16(imgOut, thisGlyphBitmap, ... imgIdx, glIdx, textColor); end end % update X position for next character penX=penX+int32(glyphStruct.glyphXAdvances(thisGlyphIdx_1b)); end end end %========================================================================== function spaceCharWidth = getSpaceCharWidth(glyphIdxFromCharcode, ... glyphXAdvances, fontHeightWOLinegap) % For space char, width is zero, but XAdvances is non-zero. % Note that for missing glyph, glyph index is zero (do not use zero glyph % width as an indicator of missing glyph) b1 = 1; % for converting 0-based to 1-based spaceGlyphIdx = glyphIdxFromCharcode(32+b1); if (spaceGlyphIdx==0) spaceCharWidth = int32(fontHeightWOLinegap/4); else spaceCharWidth = int32(glyphXAdvances(spaceGlyphIdx+b1)); end %========================================================================== function flag = isSimMode() flag = isempty(coder.target); %========================================================================== function errIf0(condition, msgID) coder.internal.errorIf(condition, msgID); %========================================================================== function errIf1(condition, msgID, strArg) coder.internal.errorIf(condition, msgID, strArg); %========================================================================== function str = cvstNum2Str(num) if isSimMode str = num2str(num); else % sprintf works on regular char (does not work on wide char) str1 = repmat(char(0),1,30); numDbl = double(num); coder.inline('always'); coder.cinclude('<stdio.h>'); coder.ceval('sprintf', coder.ref(str1), cstring('%0.5g'), numDbl); str = mstring(str1); end %========================================================================== % Put a C termination character '\0' at the end of MATLAB string function y = cstring(x) y = [x char(0)]; %========================================================================== % Remove trailing null termination characters '\0' at the end of C string function mStr = mstring(cStr) endIdx = 0; for i=1:length(cStr) if (double(cStr(i)) == double(char(0))) endIdx = i-1; break; end end mStr = cStr(1:endIdx); %========================================================================== function imgOut = doGlyph_float(imgIn, thisGlyphBitmap, ... imgIdx, glIdx, textColor) imgOut = imgIn; numPLanes = size(imgIn, 3); startR_im = imgIdx.startR_im; startC_im = imgIdx.startC_im; endR_im = imgIdx.endR_im; endC_im = imgIdx.endC_im; startR_gl = glIdx.startR_gl; startC_gl = glIdx.startC_gl; endR_gl = glIdx.endR_gl; endC_gl = glIdx.endC_gl; thisGlyphCut_u8 = thisGlyphBitmap(startR_gl:endR_gl, startC_gl:endC_gl); thisGlyphCut_float = double(thisGlyphCut_u8)/255; for idx=1:numPLanes cg = 1; for c = startC_im:endC_im rg = 1; for r = startR_im:endR_im glyphVal = thisGlyphCut_float(rg,cg); if (glyphVal == 1) imgOut(r,c,idx) = textColor(idx); elseif (glyphVal ~= 0) imgOut(r,c,idx)=(textColor(idx)-imgOut(r,c,idx))*glyphVal ... + imgOut(r,c,idx); end rg = rg+1; end cg = cg+1; end end %========================================================================== function imgOut = doGlyph_uint8(imgIn, thisGlyphBitmap, ... imgIdx, glIdx, textColor) MAX_VAL_DT = uint16(255); imgOut = imgIn; numPLanes = size(imgIn, 3); startR_im = imgIdx.startR_im; startC_im = imgIdx.startC_im; endR_im = imgIdx.endR_im; endC_im = imgIdx.endC_im; startR_gl = glIdx.startR_gl; startC_gl = glIdx.startC_gl; endR_gl = glIdx.endR_gl; endC_gl = glIdx.endC_gl; WhiteU8 = uint8(255); BlackU8 = uint8(0); thisGlyphCut_u8 = thisGlyphBitmap(startR_gl:endR_gl, startC_gl:endC_gl); for idx=1:numPLanes % max value of product of two uint8 takes uint16; so % do the computation on uint16 cg = 1; for c = startC_im:endC_im rg = 1; for r = startR_im:endR_im glyphVal = thisGlyphCut_u8(rg,cg); if (glyphVal == WhiteU8) imgOut(r,c,idx) = textColor(idx); elseif (glyphVal ~= BlackU8) tmp1 = uint16(imgOut(r,c,idx)) .* ... uint16(MAX_VAL_DT - uint16(glyphVal)); tmp2 = tmp1 + uint16 (uint16(textColor(idx)) * ... uint16(glyphVal)); tmp3 = uint16(tmp2/MAX_VAL_DT); imgOut(r,c,idx) = tmp3; end rg = rg+1; end cg = cg+1; end end %========================================================================== function imgOut = doGlyph_uint16(imgIn, thisGlyphBitmap, ... imgIdx, glIdx, textColor) MAX_VAL_DT = uint32(65535); imgOut = imgIn; numPLanes = size(imgIn, 3); startR_im = imgIdx.startR_im; startC_im = imgIdx.startC_im; endR_im = imgIdx.endR_im; endC_im = imgIdx.endC_im; startR_gl = glIdx.startR_gl; startC_gl = glIdx.startC_gl; endR_gl = glIdx.endR_gl; endC_gl = glIdx.endC_gl; thisGlyphCut_u8 = thisGlyphBitmap(startR_gl:endR_gl, startC_gl:endC_gl); thisGlyphCut_u16 = im2uint16(thisGlyphCut_u8); for idx=1:numPLanes % max value of product of two uint8 takes uint16; so % do the computation on uint16 cg = 1; for c = startC_im:endC_im rg = 1; for r = startR_im:endR_im glyphVal = thisGlyphCut_u16(rg,cg); if (glyphVal == uint16(65535)) imgOut(r,c,idx) = textColor(idx); elseif (glyphVal ~= uint16(0)) tmp1 = uint32(imgOut(r,c,idx)) .* ... uint32(MAX_VAL_DT - uint32(glyphVal)); tmp2 = tmp1 + uint32(uint32(textColor(idx)) * ... uint32(glyphVal)); tmp3 = uint32(tmp2/MAX_VAL_DT); imgOut(r,c,idx) = tmp3; end rg = rg+1; end cg = cg+1; end end %========================================================================== function imgOut = doGlyph_int16(imgIn, thisGlyphBitmap, ... imgIdx, glIdx, textColor) imgOut = imgIn; numPLanes = size(imgIn, 3); startR_im = imgIdx.startR_im; startC_im = imgIdx.startC_im; endR_im = imgIdx.endR_im; endC_im = imgIdx.endC_im; startR_gl = glIdx.startR_gl; startC_gl = glIdx.startC_gl; endR_gl = glIdx.endR_gl; endC_gl = glIdx.endC_gl; MAX_VAL_DT = uint32(65535); textColor_u16 = im2uint16(textColor); thisGlyphCut_u8 = thisGlyphBitmap(startR_gl:endR_gl, startC_gl:endC_gl); thisGlyphCut_u16 = im2uint16(thisGlyphCut_u8); for idx=1:numPLanes % max value of product of two uint8 takes uint16; so % do the computation on uint16 cg = 1; for c = startC_im:endC_im rg = 1; for r = startR_im:endR_im glyphVal = thisGlyphCut_u16(rg,cg); if (glyphVal == uint16(65535)) imgOut(r,c,idx) = textColor(idx); elseif (glyphVal ~= uint16(0)) tmp1 = uint32(im2uint16(imgOut(r,c,idx))) .* ... uint32(MAX_VAL_DT - uint32(glyphVal)); tmp2 = tmp1 + uint32(uint32(textColor_u16(idx)) * ... uint32(glyphVal)); tmp3 = uint32(tmp2/MAX_VAL_DT); imgOut(r,c,idx) = im2int16(uint16(tmp3)); end rg = rg+1; end cg = cg+1; end end