6

I have this matlab code to display image object after do super spectrogram (stft, couple plca...)

 t = z2 *stft_options.hop/stft_options.sr;
 f = stft_options.sr*[0:size(spec_t,1)-1]/stft_options.N/1000;

 max_val = max(max(db(abs(spec_t))));
 imagesc(t, f, db(abs(spec_t)),[max_val-60 max_val]); 

And get this result:

enter image description here

I was porting to C++ successfully by using Armadillo lib and get the mat results:

mat f,t,spec_t;

The problem is that I don't have any idea for converting bitmap like imagesc in matlab.

I searched and found this answer, but seems it doesn't work in my case because:

  • I use a double matrix instead of integer matrix, which can't be mark as bitmap color
  • The imagesc method take 4 parameters, which has the bounds with vectors x and y
  • The imagesc method also support scale ( I actually don't know how it work)


Does anyone have any suggestion?

Update: Here is the result of save method in Armadillo. It doesn't look like spectrogram image above. Do I miss something?

spec_t.save("spec_t.png", pgm_binary); 

enter image description here

Update 2: save spectrogram with db and abs

  mat spec_t_mag = db(abs(spec_t)); // where db method: m = 10 * log10(m);
  mag_spec_t.save("mag_spec_t.png", pgm_binary);

And the result:

enter image description here

Community
  • 1
  • 1
ductran
  • 10,043
  • 19
  • 82
  • 165
  • For the `double` matrix, you can do like `imagesc` or many other Matlab graphic functions: Project your matrix value range to a colormap made of integers. Look at Matlab documentation about [indexed colors](http://uk.mathworks.com/help/releases/R2015a/matlab/ref/graphics_i12.gif), in the `imagesc` documentation. It's a simple scaling exercise. – Hoki Aug 03 '15 at 15:13

2 Answers2

3

Armadillo is a linear algebra package, AFAIK it does not provide graphics routines. If you use something like opencv for those then it is really simple.

See this link about opencv's imshow(), and this link on how to use it in a program.

Note that opencv (like most other libraries) uses row-major indexing (x,y) and Armadillo uses column-major (row,column) indexing, as explained here.

For scaling, it's safest to convert to unsigned char yourself. In Armadillo that would be something like:

arma::Mat<unsigned char> mat2=255*(mat-mat.min())/(mat.max()-mat.min());

The t and f variables are for setting the axes, they are not part of the bitmap.

For just writing an image you can use Armadillo. Here is a description on how to write portable grey map (PGM) and portable pixel map (PPM) images. PGM export is only possible for 2D matrices, PPM export only for 3D matrices, where the 3rd dimension (size 3) are the channels for red, green and blue.

The reason your matlab figure looks prettier is because it has a colour map: a mapping of every value 0..255 to a vector [R, G, B] specifying the relative intensity of red, green and blue. A photo has an RGB value at every point:

colormap(gray);
x=imread('onion.png');
imagesc(x);
size(x)

That's the 3rd dimension of the image.

Your matrix is a 2d image, so the most natural way to show it is as grey levels (as happened for your spectrum).

x=mean(x,3);
imagesc(x);

This means that the R, G and B intensities jointly increase with the values in mat. You can put a colour map of different R,G,B combinations in a variable and use that instead, i.e. y=colormap('hot');colormap(y);. The variable y shows the R,G,B combinations for the (rescaled) image values.

It's also possible to make your own colour map (in matlab you can specify 64 R, G, and B combinations with values between 0 and 1):

z[63:-1:0; 1:2:63 63:-2:0; 0:63]'/63
colormap(z);

Now for increasing image values, red intensities decrease (starting from the maximum level), green intensities quickly increase then decrease, and blue values increase from minuimum to maximum.

Because PPM appears (I don't know the format) not to support colour maps, you need to specify the R,G,B values in a 3D array. For a colour order similar to z you would neet to make a Cube<unsigned char> c(ysize, xsize, 3) and then for every pixel y, x in mat2, do:

c(y,x,0) = 255-mat2(y,x);
c(y,x,1) = 255-abs(255-2*mat2(y,x));
x(y,x,2) = mat2(y,x)

or something very similar.

alle_meije
  • 2,424
  • 1
  • 19
  • 40
  • Thanks, but I want to save bitmap to png file instead of showing in window. Does opencv support it? – ductran Aug 04 '15 at 12:05
  • Ah, you said you wanted to do the same as imagesc which is displaying a matrix as a bitmap. saving the contents of a figure window is GUI functionality. See the link in the edit on how to write P{GP}M images in Armadillo. – alle_meije Aug 04 '15 at 13:29
  • I update my question with `save` result. But the spectrogram doesn't look like what I expect like `imagesc` on matlab. Do I miss something? My result data is complex double (because I do fft) . – ductran Aug 05 '15 at 04:01
  • Complex data don't work with imagesc. Just try `a=ones(2);imagesc(a);` and then `b=a+i*a;imagesc(b);`. In your example `abs(spect)` produces magnitudes; those are not complex. Then `db` converts to decibels, i.e. y=10*x --> db(y)=db(x)+20. That does not produce complex numbers from real data. Not sure what the Armadillo equivalent of db is, but `abs()` works as expected and so do `log10()` and `square()` (see 'misc' in the API reference). – alle_meije Aug 05 '15 at 09:16
  • Thank you. I get it. I updated my question with `abs` & `db` (refer http://www.mathworks.com/help/signal/ref/db.html) and look like it worked. But do you know how to turn color spectrogram in Armadillo? Like the range color param `[max_val-60 max_val]` on `imagesc`. Seems `ppm_binary` is for cube only, I don't know how to set a color range for it. – ductran Aug 05 '15 at 14:47
  • once you have your `arma::Mat` as above, where every matrix element is a value 0..255, 0 corrseponding to `mat.min()` and 255 corresponding to `mat.max()`, you can attribute a vector [R,G,B] to every point -- much like you do with the `colormap` variable in matlab. – alle_meije Aug 05 '15 at 15:16
  • well, I can get the scale matrix like this: `mat spec_t_scale= 255 * (mag_spec_t - mag_spec_t.min() ) / (mag_spec_t.max() - mag_spec_t.min() )`. But can you tell how I can map them with color map in `save` method Armadillo? I really don't understand. Do I need to put it into slice of `Cube`? – ductran Aug 05 '15 at 16:16
  • Yes, see the edit. Instead of using a colour map, you need to explicitly write the R, G, and B value (0..255) at every pixel. `cube(0,0,0)` is the red value at `mat(0,0)`, `cube (0,0,1)` green and `cube(0,0,2)` blue. `cube (0,1,0)` is red at `mat(0,1)` etc. – alle_meije Aug 05 '15 at 18:26
  • Try [this](http://coliru.stacked-crooked.com/a/7cb3cf0d75812250) on your own computer. On mine it creates a small coloured image. – alle_meije Aug 06 '15 at 09:51
  • Your code is worked. But how can I apply it in my code? I tried this way http://pastebin.com/3w5QMwiq and get the exception `size is fixed and hence cannot be changed` Look like I need a for statement to update color of each cube element? – ductran Aug 06 '15 at 12:44
  • These are things you caln look up in the Armadillo API. `size()` is for vectors not matrices. Why not start by just using those numbers??? This discussion is getting too long -- if you're getting properly stuck (not trivial API things) try chatting... – alle_meije Aug 06 '15 at 13:28
  • Please go to this for chatting: http://chat.stackoverflow.com/rooms/85304/discussion-between-alle-meije-and-r4j – ductran Aug 06 '15 at 13:40
  • Thanks for your help and for your patient. I get it now. I'll try and update the result later – ductran Aug 16 '15 at 07:40
  • I got your scaling to work but had to use `arma::Mat m2=arma::conv_to>::from( 255*(mat-mat.min())/(mat.max()-mat.min()) );` – Bruce Dean Sep 15 '16 at 02:37
  • Are you referring to the code snippet from 16 August at 9.51? That has no variable `m2`. It compiles if you add the `-larmadillo` directive – alle_meije Sep 16 '16 at 09:47
3

You may use SigPack, a signal processing library on top of Armadillo. It has spectrogram support and you may save the plot to a lot of different formats (png, ps, eps, tex, pdf, svg, emf, gif). SigPack uses Gnuplot for the plotting.

mtall
  • 3,574
  • 15
  • 23
Claes Rolen
  • 1,446
  • 1
  • 9
  • 21