Question

Voici le problème: j'ai un périphérique matériel personnalisé et je dois en tirer des images en C # / WPF et les afficher dans une fenêtre, le tout avec 120+ ips.

Le problème est qu'il n'y a pas d'événement pour indiquer que les images sont prêtes, mais je dois constamment interroger l'appareil et vérifier s'il y a de nouvelles images, puis les télécharger.

Il y a apparemment une poignée de façons de le faire, mais je n'ai pas encore pu trouver le bon.

Voici ce que j'ai essayé:

  • Une minuterie simple (ou DispatcheTtimer) - fonctionne très bien pour les fréquences d'images plus lentes, mais je ne peux pas le dépasser, disons, 60 ips.

  • Une seule boucle infinie filetée - assez rapide mais je dois mettre les dovents / c'est l'équivalent WPF dans la boucle pour que la fenêtre soit redessinée; Cela a d'autres conséquences indésirables (étranges) telles que les événements de presse de touches de certains contrôles qui n'étaient pas licenciés, etc.

  • Faire du sondage / téléchargement dans un autre fil et affichage dans le fil d'interface utilisateur, quelque chose comme ceci:

     new Thread(() =>
            {
                while (StillCapturing)
                {
                    if (Camera.CheckForAndDownloadImage(CameraInstance))
                    {
                        this.Dispatcher.Invoke((Action)this.DisplayImage);
                    }
                }
            }).Start();
    

    Eh bien, cela fonctionne relativement bien, mais met une charge sur un processeur et bien sûr tue complètement la machine s'il n'a pas plus d'un processeur / noyau, ce qui est inacceptable. De plus, il y a un grand nombre d'affrontements de threads de cette façon.

La question est évidente - y a-t-il de meilleures alternatives, ou est-ce que l'une de ces moyens à suivre dans ce cas?

Mise à jour:
J'ai en quelque sorte oublié de mentionner cela (eh bien, j'ai oublié d'y penser en écrivant cette question), mais bien sûr je n'ai pas besoin tout Des cadres à afficher, mais j'ai encore besoin de les capturer tous afin qu'ils puissent être enregistrés sur un disque dur.

Mise à jour 2:J'ai découvert que la méthode DispatcheTrimer est lent non pas parce qu'il ne peut pas tout traiter assez rapidement, mais parce que le Dispatchertimer attend la prochaine synchronisation verticale avant de tirer l'événement de tick; Ce qui est en fait bon dans mon cas, car dans l'événement Tick, je peux enregistrer toutes les images en attente dans un tampon de mémoire (utilisé pour enregistrer les images sur disque) et afficher le dernier.

Quant aux anciens ordinateurs complètement "tués" en capturant, il semble que WPF revienne au rendu logiciel, ce qui est très lent. Je ne peux probablement rien faire.

Merci pour toutes les réponses.

Était-ce utile?

La solution

Je pense que vous essayez trop simpliste d'une approche. Voici ce que je ferais.

a) Mettez un fil.

b) Mettez à jour uniquement l'affichage avec chaque 5ème trame. Cela réduira la quantité de traitement car je ne suis pas sûr que WPF soit conçu pour gérer bien plus de 60 images par seconde.

c) Utilisez Threadpool pour engendrer une sous-tâche pour chaque trame qui ira ensuite la sauvegarder sur le disque (dans un fichier séparé par trame), de cette façon, vous ne serez pas aussi limité par les performances du disque. Des cadres supplémentaires s'accumuleront en mémoire.

Personnellement, je les implémenterais dans cet ordre. Il y a de fortes chances que A ou B résoudra vos problèmes.

Autres conseils

Vous pouvez effectuer ce qui suit (tous les psudocode): 1. Demandez à un thread de travail fonctionnant sur le processus de capture:

List<Image> _captures = new List<Image>();
 new Thread(() =>
    {
        while (StillCapturing)
        {
            if (Camera.CheckForAndDownloadImage(CameraInstance))
            {
                lock(_locker){_captures.Add(DisplayImage);


            }
        }
    }).Start();
  1. Demandez au thread de minuteur de répartiteur de prendre la dernière image capturée (évidemment, il aura manqué quelques captures depuis la dernière tique) et afficher. Par conséquent, le fil d'interface utilisateur est étranglé et fait le moins possible, il ne fait pas toute la "capture", ceci est fait par les fils de travail. Désolé, je ne peux pas faire formater ce bit (mais vous avez l'idée):

    void OnTimerTick(can't remember params)
    

    {Image ImageToDisplay; Lock (_Locker) {ImageToDisplay = _Captures [K.Count - 1]; DisplayFunction (ImageToDisplay); }

  2. Il se peut que la liste soit une file d'attente et qu'un autre fil est utilisé pour saigner la file d'attente et écrire sur le disque ou autre chose.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top