如何在 Racket 中构建一个显示图像位图及其直方图的界面?
How to build a interface that displays an image bitmap and it's histogram in Racket?
我正在尝试构建一个 GUI,我可以在其中加载图像(并将其绘制在 canvas 上)并在按下按钮时用它的像素制作直方图(我也想在 GUI 上显示直方图,但为了简单起见,只显示“红色”像素。
最初我为图像 canvas 设置了黑色背景,之后 canvas 会根据加载的图像(使用加载按钮)进行更新。同时我还将像素保存到输入缓冲区中。
我找不到将绘图嵌入 GUI 的方法,所以现在我只在 REPL 中绘制它。
我假设图像是 256x256(但其他任何都可以,因为之后可以修改)。这是我到目前为止尝试过的代码:
#lang racket/gui
(require plot)
(define SIZE 256)
(define frame
(new frame%
[label "BMP"]
[x 0] [y 0]
[width 1000] [height 500]))
(define main-panel
(new horizontal-panel%
[parent frame]))
;---------------FOR THE IMAGE---------------------
(define input-panel
(new vertical-panel%
[parent main-panel]))
;in order to put a black fundal for the bitmap initially
(define input-bitmap (make-bitmap SIZE SIZE))
(define input-dc (send input-bitmap make-dc))
(send input-dc set-background (make-color 0 0 0))
(send input-dc clear)
(define input-canvas
(new canvas%
[parent input-panel]
[paint-callback
(λ (canvas dc)
(send dc draw-bitmap input-bitmap 0 0))]))
;update canvas with the new loaded image
;also save the pixels in the input-buffer
(define input-buffer (make-bytes (* SIZE SIZE 4)))
(define load-button
(new button%
[parent input-panel]
[label "Load file"]
[callback
(λ (button event)
(define path (get-file))
(when path
(set! input-bitmap (read-bitmap path))
(send input-canvas on-paint)
(send input-bitmap get-argb-pixels 0 0 SIZE SIZE input-buffer)))]))
;---------------FOR THE HISTOGRAM---------------------
;builds a list of SIZE elements holding the frequency of each pixels
;e.g.: '((0 100) (1 50) ... (255 75)) ->this is given to the histogram
(define (get-red-pixels buffer)
(define red-pixels
(for/list ([i (in-range 1 (* SIZE SIZE 4) 4)])
(bytes-ref buffer i)))
(map list (build-list SIZE values)
(for/list ([i SIZE])
(length (filter (λ(x) (= i x)) red-pixels)))))
(define (plot-histogram)
(plot (discrete-histogram (get-red-pixels input-buffer)
#:y-max 100
#:color 1 #:line-color 1)))
(define histogram-panel
(new vertical-panel%
[parent main-panel]))
(define refresh-button
(new button%
[parent histogram-panel]
[label "Refresh"]
[callback
(λ (button event)
;not plotting when pressed..
;also I want the plot to be on the interface
(plot-histogram))]))
(send frame show #t)
为了绘制直方图,我必须显式调用(绘图按钮),因为刷新按钮不会绘制它。无论如何,我试图将绘图放在界面内而不是新的 window 中,但我被卡住了。如果有任何不清楚的地方,请告诉我。
我对您的旧代码进行了一些更改,这似乎有效:
(检查 load-button
和 get-red-pixels
,其余代码应该相同)
#lang racket/gui
(require plot)
(define SIZE 256)
(define frame
(new frame%
[label "BMP"]
[x 0] [y 0]
[width 1000] [height 500]))
(define main-panel
(new horizontal-panel%
[parent frame]))
;---------------FOR THE IMAGE---------------------
(define input-panel
(new vertical-panel%
[parent main-panel]))
;in order to put a black fundal for the bitmap initially
(define input-bitmap (make-bitmap SIZE SIZE))
(define input-dc (send input-bitmap make-dc))
(send input-dc set-background (make-color 0 0 0))
(send input-dc clear)
(define input-canvas
(new canvas%
[parent input-panel]
[paint-callback
(λ (canvas dc)
(send dc draw-bitmap input-bitmap 0 0))]))
;update canvas with the new loaded image
;also save the pixels in the input-buffer
(define input-buffer (make-bytes (* SIZE SIZE 4)))
(define load-button
(new button%
[parent input-panel]
[label "Load file"]
[callback
(λ (button event)
(let ((path (get-file)))
(when path
(set! input-bitmap (make-object bitmap% path))
(send input-canvas on-paint)
(send input-bitmap get-argb-pixels 0 0 SIZE SIZE input-buffer)
(plot/dc (discrete-histogram (get-red-pixels input-buffer)
#:y-max SIZE
#:color 1
#:line-color 1)
(send histogram-canvas get-dc)
0 0
SIZE SIZE))))]))
;---------------FOR THE HISTOGRAM---------------------
;builds a list of SIZE elements holding the frequency of each pixels
;e.g.: '((0 100) (1 50) ... (255 75)) ->this is given to the histogram
(define (get-red-pixels buffer)
(let ((red-pixels
(for/list ([i (in-range 1 (* SIZE SIZE 4) 4)])
(bytes-ref buffer i))))
(map list
(build-list SIZE values)
(for/list ([i SIZE])
(count (λ(x) (= i x)) red-pixels)))))
(define histogram-panel
(new vertical-panel%
[parent main-panel]))
(define histogram-canvas
(new canvas%
[parent histogram-panel]))
(send frame show #t)
我正在尝试构建一个 GUI,我可以在其中加载图像(并将其绘制在 canvas 上)并在按下按钮时用它的像素制作直方图(我也想在 GUI 上显示直方图,但为了简单起见,只显示“红色”像素。
最初我为图像 canvas 设置了黑色背景,之后 canvas 会根据加载的图像(使用加载按钮)进行更新。同时我还将像素保存到输入缓冲区中。
我找不到将绘图嵌入 GUI 的方法,所以现在我只在 REPL 中绘制它。
我假设图像是 256x256(但其他任何都可以,因为之后可以修改)。这是我到目前为止尝试过的代码:
#lang racket/gui
(require plot)
(define SIZE 256)
(define frame
(new frame%
[label "BMP"]
[x 0] [y 0]
[width 1000] [height 500]))
(define main-panel
(new horizontal-panel%
[parent frame]))
;---------------FOR THE IMAGE---------------------
(define input-panel
(new vertical-panel%
[parent main-panel]))
;in order to put a black fundal for the bitmap initially
(define input-bitmap (make-bitmap SIZE SIZE))
(define input-dc (send input-bitmap make-dc))
(send input-dc set-background (make-color 0 0 0))
(send input-dc clear)
(define input-canvas
(new canvas%
[parent input-panel]
[paint-callback
(λ (canvas dc)
(send dc draw-bitmap input-bitmap 0 0))]))
;update canvas with the new loaded image
;also save the pixels in the input-buffer
(define input-buffer (make-bytes (* SIZE SIZE 4)))
(define load-button
(new button%
[parent input-panel]
[label "Load file"]
[callback
(λ (button event)
(define path (get-file))
(when path
(set! input-bitmap (read-bitmap path))
(send input-canvas on-paint)
(send input-bitmap get-argb-pixels 0 0 SIZE SIZE input-buffer)))]))
;---------------FOR THE HISTOGRAM---------------------
;builds a list of SIZE elements holding the frequency of each pixels
;e.g.: '((0 100) (1 50) ... (255 75)) ->this is given to the histogram
(define (get-red-pixels buffer)
(define red-pixels
(for/list ([i (in-range 1 (* SIZE SIZE 4) 4)])
(bytes-ref buffer i)))
(map list (build-list SIZE values)
(for/list ([i SIZE])
(length (filter (λ(x) (= i x)) red-pixels)))))
(define (plot-histogram)
(plot (discrete-histogram (get-red-pixels input-buffer)
#:y-max 100
#:color 1 #:line-color 1)))
(define histogram-panel
(new vertical-panel%
[parent main-panel]))
(define refresh-button
(new button%
[parent histogram-panel]
[label "Refresh"]
[callback
(λ (button event)
;not plotting when pressed..
;also I want the plot to be on the interface
(plot-histogram))]))
(send frame show #t)
为了绘制直方图,我必须显式调用(绘图按钮),因为刷新按钮不会绘制它。无论如何,我试图将绘图放在界面内而不是新的 window 中,但我被卡住了。如果有任何不清楚的地方,请告诉我。
我对您的旧代码进行了一些更改,这似乎有效:
(检查 load-button
和 get-red-pixels
,其余代码应该相同)
#lang racket/gui
(require plot)
(define SIZE 256)
(define frame
(new frame%
[label "BMP"]
[x 0] [y 0]
[width 1000] [height 500]))
(define main-panel
(new horizontal-panel%
[parent frame]))
;---------------FOR THE IMAGE---------------------
(define input-panel
(new vertical-panel%
[parent main-panel]))
;in order to put a black fundal for the bitmap initially
(define input-bitmap (make-bitmap SIZE SIZE))
(define input-dc (send input-bitmap make-dc))
(send input-dc set-background (make-color 0 0 0))
(send input-dc clear)
(define input-canvas
(new canvas%
[parent input-panel]
[paint-callback
(λ (canvas dc)
(send dc draw-bitmap input-bitmap 0 0))]))
;update canvas with the new loaded image
;also save the pixels in the input-buffer
(define input-buffer (make-bytes (* SIZE SIZE 4)))
(define load-button
(new button%
[parent input-panel]
[label "Load file"]
[callback
(λ (button event)
(let ((path (get-file)))
(when path
(set! input-bitmap (make-object bitmap% path))
(send input-canvas on-paint)
(send input-bitmap get-argb-pixels 0 0 SIZE SIZE input-buffer)
(plot/dc (discrete-histogram (get-red-pixels input-buffer)
#:y-max SIZE
#:color 1
#:line-color 1)
(send histogram-canvas get-dc)
0 0
SIZE SIZE))))]))
;---------------FOR THE HISTOGRAM---------------------
;builds a list of SIZE elements holding the frequency of each pixels
;e.g.: '((0 100) (1 50) ... (255 75)) ->this is given to the histogram
(define (get-red-pixels buffer)
(let ((red-pixels
(for/list ([i (in-range 1 (* SIZE SIZE 4) 4)])
(bytes-ref buffer i))))
(map list
(build-list SIZE values)
(for/list ([i SIZE])
(count (λ(x) (= i x)) red-pixels)))))
(define histogram-panel
(new vertical-panel%
[parent main-panel]))
(define histogram-canvas
(new canvas%
[parent histogram-panel]))
(send frame show #t)