How to set frame's background in Racket? I want to change the background color of a window (for usability purposes) while still being able to place other controls in that window (and keep them fully functional).
Currently I don't see a possibility for this. I tried adding a canvas and changing its background color (which works for the canvas itself), but the canvas pushes out other controls due to the GUI toolkit's geometry management.
It would be nice also to have a way to change colors of other controls (buttons, etc.).
I didn't find anything for frame, but color of button, check-box or message can be changed, if you use bitmap in field label in their constructor. You can use some image from your PC or create that bitmap programmatically:
(require racket/gui/base)
(define frame (new frame%
(label "Example")
(width 500)
(height 500)))
(define button-bg (make-object bitmap% 100 50))
(define dc (new bitmap-dc% (bitmap button-bg)))
(send dc set-brush "green" 'solid)
(send dc set-pen "black" 3 'solid)
(send dc draw-rectangle 0 0 100 50)
(send dc draw-text "Click Me!" 20 0)
(define b (new button%
(parent frame)
(label button-bg)))
(send frame show #t)
The GUI is cross platform - and some platforms do not support changing the background color.
https://lists.racket-lang.org/users/archive/2012-February/050626.html
I'm sure there is something simple, yet critical missing in my three.js fundamentals.
I have an eyeball always looking at the user's mouse cursor. I have it working based on a post by mr. doob, but I'm not exactly sure why/how it's working. Can someone please explain to me the math behind converting the screen coords to a scene space position. Below is my working example. I understand normalizing the mouse position, but then why do we (* 2-1), and -(* 2 + 1)?
window.addEventListener('mousemove', function(e){
var mouse3D = new THREE.Vector3(
( event.clientX / window.innerWidth ) * 2 - 1,
- ( event.clientY / window.innerHeight ) * 2 + 1,
0.5 );
pupil.lookAt(mouse3D);
})
TIA for your explanations! I really appreciate it.
The default 3D space runs from -1 to 1 along X, Y, and Z, and is centered at (0,0,0).
That code:
Converts X to the range [0,1], meaning the left edge corresponds to 0 and the right edge corresponds to 1 (( event.clientX / window.innerWidth ))
Then scales X to [0,2] (* 2)
Then shifts it to the range [-1,1] (- 1)
Converts Y to the range [-1,0], meaning the top edge corresponds to 0 and the bottom edge corresponds to -1 (-( event.clientY / window.innerHeight ))
Then scales Y to [-2,0] (* 2)
Then shifts it to the range [-1,1] (+ 1)
Uses a constant Z of 0.5 (within the range [-1,1]), since this is a 2D function.
I'm using the Racket GUI to write text in the window of my program.
Until now I only needed to draw text horizontally. But now I would also want to write text vertically. I saw in the documentation we can give an "angle" argument when we send the message "draw-text" to the drawing context.
Here's my little function to draw text :
(define (draw-text text fontsize x y color [rotate-angle 0.0])
(when (string? color)
(set! color (send the-color-database find-color color)))
(send bitmap-dc set-font (make-object font% fontsize 'default))
(send bitmap-dc set-text-foreground color)
(send bitmap-dc draw-text text x y [angle rotate-angle])
(update-callback))
But when I call the "draw-text" procedure with example given an angle of 90° (so that the text would be vertically) it doesn't change anything.
It's just displayed as before, horizontally.
Does someone know what's wrong?
It's not clear from the example, but did you remember to convert the 90 degrees into radians? The convention is that 360 degrees is the same as 2pi radians. Or dividing by 360, we get that 1 degree is 2pi/360 radians.
Multiplying by 90, the result is that 90 degrees is 90*2*pi/360 = 180pi/260 = pi/2 ~ 1.5707963267948966. That is, to rotate the text 90 degrees, use 1.5707963267948966 as the rotate-angle.
Also (send bitmap-dc draw-text text x y [angle rotate-angle])
should be
(send bitmap-dc draw-text text x y combine? offset? angle])
For example:
(send bitmap-dc draw-text "A text" 100 100 #t 0 1.570])
How to draw an arrow in a frame in racket (DrRacket)? For example between two objects: a circle and a rectangle obtained by:
(send dc draw-ellipse 50 50 30 30) and (send dc draw-rectangle 200 200 30 6)
You can use picts to do such things.
First, you define your picts.
(define pict-a (rectangle 40 40))
(define pict-b (circle 40))
Then you combine them to be able to use rc-find or lc-find, which are the procedures that will help you connect those picts.
(define combined (hc-append 200 pict-a pict-b))
Finally
> (pin-arrows-line 30 combined
pict-a rc-find
pict-b lc-find
#:start-angle (/ pi 11)
#:end-angle (- (/ pi 11))
#:solid? #f)
Will produce this:
You can find more information in the docs! Tell us if that solved your problem!
What kind of arrows?
For simple arrows use draw-line directly.
For bended arrows use draw-spline.
Use a filled triangle as a simple arrow head.
If you need a prettier arrow head shape,
one option is to adapt the arrow shape from MetaPict.
You can find other examples of arrows in MetaPict's documentation.
An example with a non-straight arrow which shows how to draw a state machine with MetaPict.
Is there anything in imagemagick or gimp or other linux compatible tool what can automatically detect individual objects on image and either return some location of object or store each object as separate image?
I have image like this one:
For other images where objects are located on a grid, I have successfully used crop operator in imagemagick, e.g. for 3x3 grid:
convert -crop 3x3# in-image.jpg out-image-%d.jpg
I cannot use crop when there is no rectangular grid, but I thought that white color should be enough for objects separation.
I would tackle this with a "Connected Components Analysis", or "Image Segmentation" approach, like this...
First, split the input image into components, specifying a minimum size (in order to remove smaller lumps) and allowing for 8-connectivity (i.e. the 8 neighbouring pixels N, NE, E, SE, S, SW, W, NW are considered neighbours) rather than 4-connectivity - which only considers N, E, S and W pixels connected.
convert http://i.stack.imgur.com/T2VEJ.jpg -threshold 98% \
-morphology dilate octagon \
-define connected-components:area-threshold=800 \
-define connected-components:verbose=true \
-connected-components 8 -auto-level PNG8:lumps.png
which gives this output:
Objects (id: bounding-box centroid area mean-color):
0: 450x450+0+0 219.2,222.0 93240 srgb(255,255,255)
14: 127x98+111+158 173.0,209.4 9295 srgb(0,0,0)
29: 105x91+331+303 384.1,346.9 6205 srgb(0,0,0)
8: 99x75+340+85 388.9,124.6 5817 srgb(1,1,1)
15: 110x69+330+168 385.4,204.9 5640 srgb(1,1,1)
3: 114x62+212+12 270.0,42.4 5021 srgb(0,0,0)
4: 103x63+335+12 388.9,44.9 4783 srgb(0,0,0)
11: 99x61+13+134 61.5,159.1 4181 srgb(0,0,0)
37: 128x52+313+388 375.1,418.4 4058 srgb(0,0,0)
24: 95x62+24+256 69.6,285.7 4017 srgb(0,0,0)
2: 91x68+15+12 62.0,44.4 3965 srgb(0,0,0)
38: 91x50+10+391 55.1,417.0 3884 srgb(0,0,0)
12: 83x64+249+134 288.3,168.4 3761 srgb(0,0,0)
19: 119x62+320+240 385.4,268.4 3695 srgb(9,9,9)
25: 93x63+128+268 176.1,302.1 3612 srgb(0,0,0)
39: 96x49+111+391 158.1,416.0 3610 srgb(0,0,0)
31: 104x59+117+333 172.9,360.1 3493 srgb(0,0,0)
33: 88x55+238+335 279.3,364.5 3440 srgb(0,0,0)
26: 121x54+230+271 287.6,294.0 3431 srgb(8,8,8)
1: 98x61+109+11 159.7,40.0 3355 srgb(0,0,0)
40: 88x42+218+399 262.3,419.7 3321 srgb(0,0,0)
6: 87x61+115+70 157.9,100.1 3263 srgb(0,0,0)
30: 97x57+14+327 57.3,357.2 3237 srgb(55,55,55)
17: 84x57+13+207 53.1,232.2 2995 srgb(0,0,0)
5: 107x58+10+68 58.9,97.5 2988 srgb(0,0,0)
18: 77x60+237+212 273.0,243.0 2862 srgb(0,0,0)
7: 87x49+249+78 291.8,99.3 2703 srgb(9,9,9)
10: 82x51+178+109 222.8,133.9 2628 srgb(0,0,0)
Each line corresponds to a separate component, or segment, and shows the widths and heights of the bounding boxes for each component, and their offsets from the top-left corner. You can parse that easily enough with awk and draw the indicated red boxes onto the image to give this:
The output image is called lumps.png and it looks like this:
and you can see that each component (piece of meat) has a different grey level associated with it. You can also analyse lumps.png, and extract a separate mask for each piece of meat, like this:
#!/bin/bash
# Extract every grey level, and montage together all that are not entirely black
rm mask_*png 2> /dev/null
mask=0
for v in {1..255}; do
((l=v*255))
((h=l+255))
mean=$(convert lumps.png -black-threshold "$l" -white-threshold "$h" -fill black -opaque white -threshold 1 -verbose info: | grep -c "mean: 0 ")
if [ "$mean" -eq 0 ]; then
convert lumps.png -black-threshold "$l" -white-threshold "$h" -fill black -opaque white -threshold 1 mask_$mask.png
((mask++))
fi
done
That gives us masks like this:
and this
we can see them all together if we do this
montage -tile 4x mask_* montage_masks.png
If we now apply each of the masks to the input image as the opacity and trim the resulting image, we will be left with the individual lumps of meat
seg=0
rm segment_*png 2> /dev/null
for f in mask_*png; do
convert http://i.stack.imgur.com/T2VEJ.jpg $f -compose copy-opacity -composite -trim +repage segment_$seg.png
((seg++))
done
And they will look like this:
and this
Or, we can put them all together like this:
montage -background white -tile 4x segment_* montage_results.png
Cool question :-)
It can be done with ImageMagick in multiple steps. The orignal image is named meat.jpg:
convert meat.jpg -threshold 98% -morphology Dilate Octagon meat_0.png
convert meat_0.png text: | grep -m 1 black
This gives you a pixel location in the area of the first part of meat:
131,11: ( 0, 0, 0) #000000 black
We'll use this to color the first piece in red, separate the red channel and then create and apply the mask for the first piece:
convert meat_0.png -fill red -bordercolor white \
-draw 'color 131,11 filltoborder' meat_1_red.png
convert meat_1_red.png -channel R -separate meat_1.png
convert meat_1_red.png meat_1.png -compose subtract \
-threshold 50% -composite -morphology Dilate Octagon \
-negate meat_1_mask.png
convert meat_1_mask.png meat.jpg -compose Screen -composite \
-trim meat_1.jpg
The resulting meat_1.jpg is already trimmed. You can then proceed the same way with meat_1.png in stead of meat_0.png, generating meat_2.png as the basis for successive iterations on the fly. Maybe this can be further simplified and wrapped in a shell script.
With GIMP, you can do it the following way:
Use the Magic Wand (Select Contiguous Regions tool) and select your background;
Menu Select > Invert to get multiple selections;
Install the script-fu export-selected-regions below if you don't have it yet;
Menu Select > Export Selected Regions, your new images should be in the same folder as the original one.
If you're using GIMP 2.10 on mac, put the script below in: ~/Library/Application\ Support/GIMP/2.10/scripts/export-selected-regions.scm, check for the appropriate folder for other system.
;;; Non-interactively save all selected regions as separate files
(define (script-fu-export-selected-regions image drawable)
;; Start
(gimp-image-undo-group-start image)
;; If there are selections
(when (= 0 (car (gimp-selection-is-empty image)))
(let ((number 1) (prefix "") (suffix ""))
;; Construct filename components
(let* ((parts (strbreakup (car (gimp-image-get-filename image)) "."))
(coextension (unbreakupstr (reverse (cdr (reverse parts))) "."))
(extension (cadr parts)))
(set! prefix (string-append coextension "_selection-" ))
(set! suffix (string-append "." extension)))
;; Convert all selections to a single path
(plug-in-sel2path RUN-NONINTERACTIVE image drawable)
;; For each stroke in the path
(let ((vectors (vector-ref (cadr (gimp-image-get-vectors image)) 0)))
(for-each (lambda (stroke)
;; Convert the stroke back into a selection
(let ((buffer (car (gimp-vectors-new image "buffer")))
(points (gimp-vectors-stroke-get-points vectors stroke)))
(gimp-image-insert-vectors image buffer 0 -1)
(apply gimp-vectors-stroke-new-from-points buffer points)
(gimp-vectors-to-selection buffer 2 TRUE FALSE 0 0)
(gimp-image-remove-vectors image buffer))
;; Replace the selection with its bounding box
(apply (lambda (x0 y0 x1 y1)
(gimp-image-select-rectangle image 2 x0 y0 (- x1 x0) (- y1 y0)))
(cdr (gimp-selection-bounds image)))
;; Extract and save the contents as a new file
(gimp-edit-copy drawable)
(let* ((image (car (gimp-edit-paste-as-new)))
(drawable (car (gimp-image-get-active-layer image)))
(filename ""))
(while (or (equal? "" filename) (file-exists? filename))
(let* ((digits (number->string number))
(zeros (substring "0000" (string-length digits))))
(set! filename (string-append prefix zeros digits suffix)))
(set! number (+ number 1)))
(gimp-file-save RUN-NONINTERACTIVE image drawable filename filename)
(gimp-image-delete image)))
(vector->list (cadr (gimp-vectors-get-strokes vectors))))
(gimp-image-remove-vectors image vectors))))
;; End
(gimp-selection-none image)
(gimp-image-undo-group-end image))
(script-fu-register "script-fu-export-selected-regions"
"Export Selected Regions"
"Export each selected region to a separate file."
"Andrew Kvalheim <Andrew#Kvalhe.im>"
"Andrew Kvalheim <Andrew#Kvalhe.im>"
"2012"
"RGB* GRAY* INDEXED*"
SF-IMAGE "Image" 0
SF-DRAWABLE "Drawable" 0)
(script-fu-menu-register "script-fu-export-selected-regions" "<Image>/Select")
Many thanks to Andrew Kvalheim for his script-fu.