Traitement d'image avec MyHDL

Qu'est-ce que MyHDL

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

Description du traitement d'image

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.

Description dans OpenCV

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)

Image d'entrée

twi.jpg

Image de sortie

Il y a un léger flou sur le visage. twi_blur_cv.jpg

Description dans MyHDL

organisation des fichiers

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ôté banc d'essai

C'est une description côté banc d'essai.

CLK, réinitialisation, etc.

Omis car il est presque identique à l'échantillon

Enregistrer les paramètres

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

Mémoire

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)

Côté RTL

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

Résultat du traitement

Image de sortie par MyHDL

C'est presque le même résultat d'OpenCV.

twi_blur_rtl.jpg

sortie vcd

Puisque vcd peut également être émis, vous pouvez vérifier la forme d'onde avec gtkwave. Cela fonctionne comme prévu. gtkwave.png

Conversion vers Verilog

Méthode de conversion

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
    )

Résultat de la conversion

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> <

Impressions

Bon endroit

--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.

Là où ça n'a pas marché

――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

Traitement d'image avec MyHDL
Traitement d'image avec Python
Traitement d'image avec PIL
Traitement d'image avec Python (partie 2)
Traitement d'image avec PIL (Pillow)
Traitement d'image avec Python (partie 1)
Traitement d'image avec Python (3)
[Python] Traitement d'image avec scicit-image
Principes de base du traitement d'image en temps réel avec opencv
Traitement d'image avec la binarisation Python 100 knocks # 3
100 traitement d'image par Python Knock # 2 Échelle de gris
[Traitement d'image] Postérisation
traitement d'image python
Traitement d'image 100 coups ①
Bases du traitement d'images binarisées par Python
Traitement d'image par Python 100 knock # 10 filtre médian
Créer une visionneuse de traitement d'image avec PySimpleGUI
100 traitement d'image avec Python Knock # 8 Max Pooling
Traitement d'image avec Python et OpenCV [Tone Curve]
Traitement d'image par Python 100 knock # 12 motion filter
Dessin avec Matrix-Reinventor of Python Image Processing-
Traitez facilement des images en Python avec Pillow
Traitement d'image avec Python 100 knocks # 7 pooling moyen
Traitement d'image léger avec Python x OpenCV
Traitement d'image avec Lambda + OpenCV (création d'image grise)
Traitement d'image par Python 100 knock # 9 Filtre Gaussien
XavierNX accélère le traitement d'image OpenCV avec GPU (CUDA)
Traitement des ensembles de données avec des pandas (1)
Traitement des ensembles de données avec des pandas (2)
Reconnaissance d'image avec keras
Traitement d'image à partir de zéro avec python (5) Transformation de Fourier
Premier traitement d'image Python
Lire le traitement d'image numérique
Traitement d'image à partir de zéro avec python (4) Extraction de contour
Traitement d'image avec la configuration de l'environnement Python pour Windows
Traitement parallèle avec multitraitement
Remarques sur le traitement d'images HDR et RAW avec Python
Téléchargement d'image avec l'API Flickr
100 coups de traitement du langage avec Python 2015
opencv-python Introduction au traitement d'image
Lire les coordonnées de l'image avec Python-matplotlib
Traitement parallèle avec des fonctions locales
"Traitement Apple" avec OpenCV3 + Python3
Édition d'image avec python OpenCV
Traitement du signal acoustique avec Python (2)
Traitement d'image numérique (filtrage spatial)
100 coups sur le traitement d'image !! (011-020) Début de partie
Traitement du signal acoustique avec Python
Téléchargement d'images et personnalisation avec django-ckeditor
Tri des fichiers image avec Python (2)
Tri des fichiers image avec Python (3)
100 coups sur le traitement d'image !! (001 --010) Soigneusement et soigneusement
Traitement parallèle avec Parallel de scikit-learn
Créer une visionneuse d'images avec Tkinter
Tweet avec image en Python
Tri des fichiers image avec Python
Traitement d'image par python (Pillow)
Collection de traitement d'image en Python