Message Boards Message Boards

0
|
4186 Views
|
9 Replies
|
14 Total Likes
View groups...
Share
Share this post:

How superimpose text on bitmap?

Posted 2 years ago

I want to add numbered rows and columns to a color chart I produced using pixelmath in Pixinsight. But PI seems to lack facilities for automatic labeling, so I brought the chart into Mathematica as a bitmap, thinking I could superimpose text onto the bitmap in precise locations. The local documentation suggested I might be able to do this with ImageCompose[], which worked up to a point. I find that I am unable to position labels exactly where I want them. The bitmap and the graphics seem to lack common mapping. I need suggestions.

The yellow disc at the bottom center is located at the origin point. The rows of numbers are in the expected row and column, but not in their precise desired positions.

Postscript: After several comments, I have revised a bit. The user will have to add their own path or paste in the attached bitmap. To see the effect of Schachner's revision, uncomment the three rules in the Graphics[] function near the bottom.

(* BITMAP *)

path = "/Users/<username>/Documents/ASTRONOMY/JWST/COLORS/";
colorFile = StringJoin[path, "rb10.bmp"];
bitmap = Import[colorFile];

(*GLOBALS*)

(*grid parameters*)
iDims = ImageDimensions@bitmap;
imgWd = iDims[[
  1]];(*width and height of this image*)
n = 10.0;(*number rows or \
columns*)
wd = imgWd/n;(*width of row or column*)
rowStart = 
 imgWd - wd/2.0;
colStart = -imgWd/2.0 + wd/2.0;

(*text values*)
txtSz = 16; color = Yellow; face = Bold;

(*OBJECTS*)

rowTxt = 
  Table[Text[
    Style[ToString[m + 1], {txtSz, color, face}], {colStart + m*wd, 
     rowStart}], {m, Range[0, n - 1]}];
colTxt = 
  Table[Text[
    Style[ToString[m + 1], {txtSz, color, face}], {colStart, 
     rowStart - m*wd}], {m, Range[0, n - 1]}];

originPt = {Yellow, PointSize[.03],
   Point[{0, 0}]};

gr = Graphics[{rowTxt, colTxt, originPt},
   (* three lines added by Henrik Schachner: *)
   (*

   PlotRangePadding->None, 
   PlotRange->{{-imgWd/2.0,imgWd/2.0},{1,imgWd}},
   ImageSize->iDims *)

   ];

ImageCompose[bitmap, gr]

enter image description here

Attachments:
POSTED BY: Gary Palmer
9 Replies
Posted 2 years ago

I am grateful to Eric and Rohit for showing me new ways to do this. My original project involved creating the bitmap using pixelmath, which can do with a couple of lines of code, and then importing it into Mathematica to add the labels. This thread has become a useful resource for making bitmaps in Mathematica and for combining them with plotting and graphics functions, and I will refer to it in the future. As I think Henrik noticed, the two rotations in colTxt[] just canceled each other. I fixed that.

POSTED BY: Gary Palmer
Posted 2 years ago

So, I don't know your specific use case, obviously, but you might consider a completely different approach. Mathematica has many built in plotting functions, and some of them seem like they'd give you similar functionality. For example, you might want to check out DiscretePlot3D, ListPlot3D, ArrayPlot, and MatrixPlot. Here is an example...

If you have the grid of colors, then ArrayPlot and MatrixPlot will work pretty much "out of the box". Since I don't have your color data, I'll make some up. It looks like there is some blending going on, so I'll start with a helper blending function:

MakeBlendedRow[col1_, col2_, ct_] := Array[Blend[{col1, col2}, #] &, ct, {0, 1}]

I'll blend left to right to get the grid and top to bottom to get the edges:

edgeColors = {MakeBlendedRow[Black, Red, 10], MakeBlendedRow[Blue, RGBColor[0.98, 0.73, 1.], 10]};
colorGrid = MapThread[MakeBlendedRow[#1, #2, 10] &, edgeColors]

and then:

MatrixPlot[colorGrid]

enter image description here

POSTED BY: Eric Rimbey
Posted 2 years ago

To overlay numbers using Eric's answer use Epilog.

epilog = {Yellow, MapIndexed[Text[#1, {First@#2, 10} - 1/2] &, Range@10]};
MatrixPlot[colorGrid, Epilog -> epilog]

enter image description here

You can add a column of rotated text to the epilog for the vertical numbers.

POSTED BY: Rohit Namjoshi
Posted 2 years ago

Henrik, I was not much concerned with the column, but you have put your finger on the problem and fixed it. I removed lines one at a time from your revision of the Graphics[] statement, starting from the bottom. The key was your addition of PlotRange and ImageSize. I don’t understand why PlotRange should affect the positioning, as I thought it would act like a window, admitting just the portions of the image to be displayed, not how they are displayed in relation to something else, but apparently, the composition with the bitmap must be taken into account.

To show that the column itself was not causing the problem, just remove “col1” from the graphics statement. Your top row is still correct. I probably should not have included the column, which needs rotation of each number about itself anyway, but I wanted to show that both the vertical and horizontal dimensions were out of whack, and after fussing with a problem, one gets tired and careless about details. Many thanks. Gary

POSTED BY: Gary Palmer

Gary, glad to help!

I don’t understand why PlotRange should affect the positioning, ...

If you do not specify PlotRange then values are used to make the graphics just large enough to show (most of) the objects. You can check:

gr0 = Graphics[{row1, col1, originPt}, PlotRangePadding -> None, ImageSize -> iDims];
AbsoluteOptions[gr0, PlotRange]
(*   Out:    {PlotRange\[Rule]{{-460.8,460.8},{0.,972.8}}}   *)

This represents not even a square, but a rectangle!

POSTED BY: Henrik Schachner
Posted 2 years ago

Henrik, I see what you mean. Thank you. It seems a bit deficient to have a default PlotRange that does not include everything in the plot, but so long as one can specify the plot range values, there is no harm done.

POSTED BY: Gary Palmer

Gary,

besides Eric's nice solution, here is another approach:

I guess the basic problem of your code is that you define in a clean way a row of numbers - and then, less cleanly, simply rotate that to get the column of numbers. So I just add a function colText[] where just the numbers are rotated:

(*GLOBALS*)
iDims = ImageDimensions@bitmap;

(*grid parameters*)
imgWd = 1024;(*width and height of image*)n = 10.;(*number rows or columns*)
 wd = imgWd/10.;(*width of row or column*)
rowStart = imgWd - wd/2.;
colStart = -imgWd/2. + wd/2.;

(*text values*)
txtSz = 16;
color = Yellow;
face = Bold;

(*FUNCTION*)
rowTxt[row_] := 
  Table[Text[
    Style[ToString[m + 1], {txtSz, color, face}], {colStart + m*wd, (rowStart - row*wd)}], {m, Range[0, n - 1]}];
colTxt[row_] := 
  Table[Text[
    Style[Rotate[ToString[m + 1], -Pi/2], {txtSz, color, 
      face}], {colStart, (rowStart - +m*wd)}], {m, Range[1, n - 1]}];
(*OBJECTS*)
rect = Rectangle[{{0, 0}, {100, 100}}];(*does not display*)
row1 = rowTxt[0];(*should be in top row*)
col1 = colTxt[0];(*should be in column 1?*)
originPt = {Yellow, PointSize[.03], Point[{0, 0}]};
(*displays at bottom*)

(* definition of graphics: *)
gr = Graphics[{row1, col1, originPt}, PlotRangePadding -> None, 
   PlotRange -> {{-imgWd/2., imgWd/2.}, {1, imgWd}}, 
   ImageSize -> iDims];
ImageCompose[bitmap, gr]

enter image description here

POSTED BY: Henrik Schachner
Posted 2 years ago

Eric, Thanks. I will have to investigate a couple of those functions and try them out. Gary

POSTED BY: Gary Palmer
Posted 2 years ago

I would probably work with just plain images. You could create a function that creates the "cells" for each number and then assembles those into an overlay. So, for example:

MakeTextCellOverlay[dims_, styles_, text_] := 
 ColorReplace[ImageCrop[RemoveBackground[Rasterize[Style[text, styles]]], dims], White]

You can pass your desired styles and dimensions along with the text. You've already specified the styles you want. You can calculate the dimensions however you want, but I'll assume that each cell is scaled by a factor of 10 in each dimension:

cellDimensions = ImageDimensions[bitmap]/10

Now we compute the individual cells:

overlayCells = 
 MakeTextCellOverlay[cellDimensions, {16, RGBColor[1, 1, 0], Bold}, #] & /@ Range[10]

Use these to make row and column:

row = ImageAssemble[{overlayCells}];
column = ImageRotate[row, -Pi/2]

Now compose everything:

ImageCompose[ImageCompose[bitmap, column, Scaled[{.05, .5}]], row, Scaled[{.5, .05}]]

Now, I don't know what you want to do about the "collision" in the lower left corner, but hopefully this has given you enough to play with. Tweak it until you get what you want.

POSTED BY: Eric Rimbey
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract