http://www.myhdl.org/ Une bibliothèque de modélisation de matériel en Python, développée en. Cette fois, j'ai essayé de modéliser le traitement d'image en utilisant MyHDL. En termes de couches, je sentais que j'étais dans la même position que le système C.
Toutes les sources sont ici. https://github.com/natsutan/computervision/tree/master/LOCV/chap5
J'ai essayé d'ajouter un simple flou à une certaine zone de l'image d'entrée. L'algorithme utilise la valeur moyenne de 5x5 autour du pixel d'intérêt comme pixel.
J'écrirai ici rapidement en utilisant OpenCV.
def run_opencv():
src = cv2.imread('../../image/twittan/twittan.jpg')
dst = src.copy()
roi_x = 100
roi_y = 100
roi_w = 150
roi_h = 200
dst[roi_y:roi_y + roi_h, roi_x:roi_x + roi_w] = cv2.blur(src[roi_y:roi_y + roi_h, roi_x:roi_x + roi_w], (5, 5),
(-1, -1))
print("image size:width = %d, height = %d" % (dst.shape[1], dst.shape[0]))
cv2.imwrite('twi_blur_cv.jpg', dst)
Il y a un léger flou sur le visage.
Cette fois, j'utilise 5 fichiers. --smooth.py C'est tout le TOP, y compris le traitement OpenCV. Exécutez Sim avec python smoothy.py. --myhdl_top.py C'est le TOP de l'environnement MyHDL. Comprend Clk et Reset. --smooth_hdl.py RTL est répertorié. --mem.py Modèle de mémoire de simulation MyHDL. --Reg_driver.py Définit le registre.
C'est une description côté banc d'essai.
Omis car il est presque identique à l'échantillon
Puisque la réinitialisation de la logique positive ne vient que de 1clk, nous attendons qu'elle définisse le registre. Après cela, le registre de début est mis à 1 par 1clk pour démarrer le processus, et le processus se termine après avoir attendu que le registre de fin devienne 1. yield clk.posedge équivaut à wait posedge (clk);.
reg_driver.py
# -*- coding: utf-8 -*-
__author__ = 'natu'
from myhdl import *
def reg_driver_top(
clk, reset,
reg_start, reg_end,
reg_width, reg_height,
reg_roi_x, reg_roi_y, reg_roi_h, reg_roi_w
):
@instance
def regDriver():
while reset == 0:
yield clk.posedge
while reset == 1:
yield clk.posedge
reg_width.next = 358
reg_height.next = 557
reg_roi_x.next = 100
reg_roi_y.next = 100
reg_roi_h.next = 200
reg_roi_w.next = 150
yield clk.posedge
reg_start.next = 1
yield clk.posedge
reg_start.next = 0
yield clk.posedge
while reg_end == 0:
yield clk.posedge
print("end == 1")
yield clk.posedge
return regDriver
C'est là que la puissance de Python a pu être démontrée. Vous pouvez utiliser imread d'OpenCV pour ouvrir directement un fichier jpeg et l'utiliser pour Sim. Vous n'avez pas besoin de vider Hex et d'utiliser readmemh. La sortie peut également être directement convertie en image avec OpenCV.
Le côté lecture met à jour read_r, read_g et read_b lorsque radr change dans le circuit de combinaison, et le côté écriture écrit dans la mémoire lorsque wen vaut 1 dans la synchronisation clk.
mem.py
# -*- coding: utf-8 -*-
__author__ = 'natu'
from myhdl import *
import numpy
import cv2
dst = None
def mem_top(
clk, reset,
read_r, read_g, read_b, radr,
write_r, write_g, write_b, wadr, wen):
global dst
src = cv2.imread('../../image/twittan/twittan.jpg')
dst = numpy.zeros(src.shape)
@always_comb
def mem_read():
x, y = adr_dec(radr)
read_r.next = clop_8bit(src[y][x][0])
read_g.next = clop_8bit(src[y][x][1])
read_b.next = clop_8bit(src[y][x][2])
@instance
def mem_write():
while True:
if wen == 1:
x, y = adr_dec(wadr)
dst[y][x][0] = write_r
dst[y][x][1] = write_g
dst[y][x][2] = write_b
yield clk.posedge
return mem_read, mem_write
def write_image():
cv2.imwrite('twi_blur_rtl.jpg', dst)
def adr_dec(adr):
width = dst.shape[1]
x = int(adr) % width
y = int(adr) / width
return x, y
def clop_8bit(x):
if x >= 255:
return 255
return int(x)
Puisque la machine d'état était dans l'échantillon, je l'ai mise pour le moment, mais ce n'est pas un mouvement très important. Il est pratique de pouvoir utiliser pour traiter x et y.
Avec cette double boucle, nous obtenons 5x5 autour du pixel d'intérêt.
for ry in range(-2,3):
for rx in range(-2,3):
Les valeurs sont ajoutées à sum_r, sum_g et sum_b, et la valeur moyenne est calculée à // 25. Ce serait très pratique si vous pouviez le synthétiser avec juste cela.
Ci-dessous, toutes les sources
smooth_hdl.py
# -*- coding: utf-8 -*-
__author__ = 'natu'
from myhdl import *
t_State = enum('IDLE', 'RUNNING')
def smoother_top(
clk, reset,
rin, gin, bin, radr,
rout, gout, bout, wadr, wen,
reg_start, reg_end,
reg_width, reg_height,
reg_roi_x, reg_roi_y, reg_roi_h, reg_roi_w
):
state = Signal(t_State.IDLE)
@instance
def main_proc():
while 1:
if state == t_State.RUNNING:
for y in range(reg_height):
print("y = %d" % y)
for x in range(reg_width):
if reg_roi_x <= x and x < reg_roi_x + reg_roi_w and reg_roi_y <= y and y < reg_roi_y + reg_roi_h:
# ROI
sum_r = 0
sum_g = 0
sum_b = 0
for ry in range(-2,3):
for rx in range(-2,3):
radr.next = adr(x + rx, y + ry)
yield clk.posedge
sum_r = sum_r + rin
sum_g = sum_g + gin
sum_b = sum_b + bin
yield clk.posedge
wadr.next = adr(x, y)
rout.next = sum_r // 25
gout.next = sum_g // 25
bout.next = sum_b // 25
wen.next = 1
yield clk.posedge
wen.next = 0
else:
radr.next = adr(x, y)
yield clk.posedge
wadr.next = adr(x, y)
rout.next = rin
gout.next = gin
bout.next = bin
wen.next = 1
yield clk.posedge
wen.next = 0
reg_end.next = 1
yield clk.posedge
yield clk.posedge
def adr(x, y):
return y * reg_width + x
@always_seq(clk.posedge, reset=reset)
def fsm():
if state == t_State.IDLE:
if reg_start == 1:
state.next = t_State.RUNNING
elif state == t_State.RUNNING:
if reg_end == 1:
state.next = t_State.IDLE
else:
raise ValueError("Undefined state")
return fsm, main_proc
C'est presque le même résultat d'OpenCV.
Puisque vcd peut également être émis, vous pouvez vérifier la forme d'onde avec gtkwave. Cela fonctionne comme prévu.
La conversion vers Verilog est également un one-shot utilisant la fonction toVerilog. Alors que 1: est OK, alors que True est inutile, et il y avait des barrières subtiles, mais j'ai pu Verilog avec cette description.
toVerilog(smoother_top,
clk, reset,
rin, gin, bin, radr,
rout, gout, bout, wadr, wen,
reg_start, reg_end,
reg_width, reg_height,
reg_roi_x, reg_roi_y, reg_roi_h, reg_roi_w
)
C'est excitant.
// File: smoother_top.v
// Generated by MyHDL 0.9.dev0
// Date: Tue May 19 14:30:05 2015
`timescale 1ns/10ps
module smoother_top (
clk,
reset,
rin,
gin,
bin,
radr,
rout,
gout,
bout,
wadr,
wen,
reg_start,
reg_end,
reg_width,
reg_height,
reg_roi_x,
reg_roi_y,
reg_roi_h,
reg_roi_w
);
input clk;
input reset;
input [7:0] rin;
input [7:0] gin;
input [7:0] bin;
output [19:0] radr;
reg [19:0] radr;
output [7:0] rout;
reg [7:0] rout;
output [7:0] gout;
reg [7:0] gout;
output [7:0] bout;
reg [7:0] bout;
output [19:0] wadr;
reg [19:0] wadr;
output wen;
reg wen;
input reg_start;
output reg_end;
reg reg_end;
input [9:0] reg_width;
input [9:0] reg_height;
input [9:0] reg_roi_x;
input [9:0] reg_roi_y;
input [9:0] reg_roi_h;
input [9:0] reg_roi_w;
reg [0:0] state;
function integer MYHDL13_adr;
input x;
integer x;
input y;
integer y;
begin: MYHDL17_RETURN
MYHDL13_adr = ((y * $signed({1'b0, reg_width})) + x);
disable MYHDL17_RETURN;
end
endfunction
function integer MYHDL14_adr;
input x;
integer x;
input y;
integer y;
begin: MYHDL18_RETURN
MYHDL14_adr = ((y * $signed({1'b0, reg_width})) + x);
disable MYHDL18_RETURN;
end
endfunction
function integer MYHDL15_adr;
input x;
integer x;
input y;
integer y;
begin: MYHDL19_RETURN
MYHDL15_adr = ((y * $signed({1'b0, reg_width})) + x);
disable MYHDL19_RETURN;
end
endfunction
function integer MYHDL16_adr;
input x;
integer x;
input y;
integer y;
begin: MYHDL20_RETURN
MYHDL16_adr = ((y * $signed({1'b0, reg_width})) + x);
disable MYHDL20_RETURN;
end
endfunction
always @(posedge clk, posedge reset) begin: SMOOTHER_TOP_FSM
if (reset == 1) begin
state <= 1'b0;
end
else begin
case (state)
1'b0: begin
if ((reg_start == 1)) begin
state <= 1'b1;
end
end
1'b1: begin
if ((reg_end == 1)) begin
state <= 1'b0;
end
end
default: begin
$finish;
end
endcase
end
end
initial begin: SMOOTHER_TOP_MAIN_PROC
integer sum_b;
integer rx;
integer ry;
integer sum_g;
integer y;
integer x;
integer sum_r;
while (1) begin
if ((state == 1'b1)) begin
for (y=0; y<reg_height; y=y+1) begin
$write("y = ");
$write("%0d", y);
$write("\n");
for (x=0; x<reg_width; x=x+1) begin
if ((($signed({1'b0, reg_roi_x}) <= x) && (x < (reg_roi_x + reg_roi_w)) && ($signed({1'b0, reg_roi_y}) <= y) && (y < (reg_roi_y + reg_roi_h)))) begin
sum_r = 0;
sum_g = 0;
sum_b = 0;
for (ry=(-2); ry<3; ry=ry+1) begin
for (rx=(-2); rx<3; rx=rx+1) begin
radr <= MYHDL13_adr((x + rx), (y + ry));
@(posedge clk);
sum_r = (sum_r + rin);
sum_g = (sum_g + gin);
sum_b = (sum_b + bin);
@(posedge clk);
end
end
wadr <= MYHDL14_adr(x, y);
rout <= (sum_r / 25);
gout <= (sum_g / 25);
bout <= (sum_b / 25);
wen <= 1;
@(posedge clk);
wen <= 0;
end
else begin
radr <= MYHDL15_adr(x, y);
@(posedge clk);
wadr <= MYHDL16_adr(x, y);
rout <= rin;
gout <= gin;
bout <= bin;
wen <= 1;
@(posedge clk);
wen <= 0;
end
end
end
reg_end <= 1;
@(posedge clk);
end
@(posedge clk);
end
end
endmodule
initial begin: SMOOTHER_TOP_MAIN_PROC、、、
(Tsu д⊂) Gojigoshi → (; ゚ Д ゚)…! ??
Les gens Les gens Les gens Les gens Les gens > initial begin: <  ̄Y^Y^Y^Y^Y^Y^ ̄
Je ne peux pas synthétiser! Pas bon> <
--PyCharm est pratique. Il vous indique les signaux inutilisés, le remplacement par lots des variables qui comprennent la portée, etc. Cependant, dans l'état par défaut, il y a trop d'avertissements et il est difficile à utiliser. Oh, il y a beaucoup de sauts de ligne, il n'y en a pas beaucoup, et je suis agacé par l'espace ici, donc c'est un peu pénible.
Je voulais essayer les affirmations et la couverture, mais j'étais tellement débordé que je ne pouvais pas synthétiser le circuit que j'ai fait, donc je ne pouvais pas aller aussi loin.
――Il est très difficile d'écrire un circuit en mouvement. Il n'est pas intuitif de renvoyer une fonction qui décrit le comportement du circuit. Difficile à déboguer.
@always_seq(clk.posedge, reset=reset)
def fsm():
if state == t_State.IDLE:
if reg_start == 1:
state.next = t_State.RUNNING
elif state == t_State.RUNNING:
if reg_end == 1:
state.next = t_State.IDLE
else:
raise ValueError("Undefined state")
La description qui peut être synthétisée est ce modèle, et vous devez écrire un générateur qui n'inclut pas de rendement au milieu. En d'autres termes, c'est le même que Verilog-HDL. C'est juste un langage de modélisation.
Recommended Posts