Halcon: MultiThread (WPF)

翻译自Halcon/C#/Multithreading,不过,界面换成了WPF格式,外形还是一样的。

多线程中需要保证数据共享在任何时候都是有效的,这就需要用到Mutex;同时Event用于线程间的同步;

主界面代表主线程,同时,也是现实结果的地方;

当我们点击‘Start’按钮时,线程threadAcq和threadIP分别被触发,进行图像采集和图像处理;

当点击‘Stop’按钮时,StopEvent将被发送出去,导致线程结束当前的操作,关闭句柄,离开线程函数;

数据共享的部分为:

线程 对象 类型
threadAcq & threadIP image ArraryList imgList
threadIP & main thread results struct ResultContainer resultData

会用Mutex的地方:

数据名称 互斥器名称
imgList newImageMutex
resultData resultDataMutex

信号交换:

线程 1 方向 线程 2 信号
threadAcq -- > threadIP newImageEvent
threadIP -- > main thread newResultEvent
threadIP < -- main thread containerIsFreeEvent

当然,所有的线程会监听StopEvent信号。

1)主界面分两行

<Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="60"/>
</Grid.RowDefinitions>

2)第一行(0,0)又分为一行两列

<Grid Grid.Row="0" Grid.Column="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition Width="180"/>
            </Grid.ColumnDefinitions>
            <StackPanel Grid.Row="0" Grid.Column="0" VerticalAlignment="Center">
                <ip:HSmartWindowControlWPF Name="hWindow" Width="384" Height="259"/>
            </StackPanel>
            <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
                <Button Name="btnStart" Content="Start" Click="btnStart_Click" Width="100" Height="40" Margin="10,10,10,10"/>
                <Button Name="btnStop" Content="Stop" Click="btnStop_Click" Width="100" Height="40" Margin="10,10,10,10"/>
            </StackPanel>
</Grid>

上面包括一个Halcon窗体,和右边的两个按钮;

3)第二行(1,0)又分为两行两列

<Grid Grid.Row="1" Grid.Column="0">
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="135"/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <StackPanel Grid.Row="0" Grid.Column="0">
                <Label Name="lbl1" Content="Processing Time: " HorizontalAlignment="Left"/>
            </StackPanel>
            <StackPanel Grid.Row="0" Grid.Column="1">
                <Label Name="lblProcessTime" Content="" HorizontalAlignment="Left"/>
            </StackPanel>
            <StackPanel Grid.Row="1" Grid.Column="0">
                <Label Name="lbl2" Content="Data Code Content: " HorizontalAlignment="Left"/>
            </StackPanel>
            <StackPanel Grid.Row="1" Grid.Column="1">
                <Label Name="lblData" Content="" HorizontalAlignment="Left"/>
            </StackPanel>
</Grid>

用于显示结果;

4)界面显示:


5)图像采集部分:异步读取图像;等待newImgMutex;添加图像到列表(知道读满);释放newImageMutex;设定信号newImgEvent为On(知会图像处理线程);检查Stop信号,如有,则立即退出;

public void ImgAcqRun()
{
            // -------------------  INIT ----------------
            string sequenceName = "datacode/ecc200/ecc200.seq";

            HFramegrabber acquisition = new HFramegrabber("File", 1, 1, 0, 0, 0, 0,
              "default", -1, "default", -1, "default", sequenceName, "default", -1, -1);

            // -----------  WAIT FOR EVENTS  ---------------
            while (true)
            {
                HImage grabbedImage = acquisition.GrabImageAsync(-1);

                newImgMutex.WaitOne();                // CriticalSect
                if (imgList.Count < MAX_BUFFERS)      
                {                                     
                    imgList.Add(grabbedImage);
                }
                else
                {
                    grabbedImage.Dispose();
                }                                     
                newImgMutex.ReleaseMutex();           // CriticalSect

                newImgEvent.Set();

                if (delegatedStopEvent.WaitOne(0, true)) break;
            }

            // --------  RESET/CLOSE ALL HANDLES  ---------
            acquisition.Dispose();
            newImgEvent.Reset();

            return;
}

6)图像处理部分:等待图像互斥器newImgMutex;取列表中的第一张图像并移除;释放互斥器;读取二维码;等待信号containerIsFreeEvent(也就是上一组数据是否已显示完毕);填写数据到Container;释放互斥器;发送信号newResultEvent(通知主线程可以更新数据了);也是要时刻监控Stop信号。

public void IPRun()
{
            // -------------------  INIT ----------------
            HDataCode2D reader = new HDataCode2D("Data Matrix ECC 200",
              new HTuple(), new HTuple());

            reader.SetDataCode2dParam("default_parameters", "enhanced_recognition");

            // -----------  WAIT FOR EVENTS  ---------------
            while (newImgEvent.WaitOne())
            {
                newImgMutex.WaitOne();              // CriticalSect
                HImage image = (HImage)imgList[0];  // CriticalSect
                imgList.Remove(image);              // CriticalSect
                newImgMutex.ReleaseMutex();         // CriticalSect

                HTuple t1 = HSystem.CountSeconds();

                HTuple decodedDataStrings, resultHandle;

                HXLD symbolXLDs = reader.FindDataCode2d(image, new HTuple(),
                  new HTuple(), out resultHandle, out decodedDataStrings);

                HTuple t2 = HSystem.CountSeconds();

                containerIsFreeEvent.WaitOne();
                resultDataMutex.WaitOne();                      // CriticalSect
                resultData.timeNeeded = (1000 * (t2 - t1));       // CriticalSect
                resultData.decodedData = decodedDataStrings;   // CriticalSect
                resultData.resultImg = image;                // CriticalSect
                resultData.resultHandle = resultHandle;         // CriticalSect
                resultData.symbolData = symbolXLDs;           // CriticalSect
                containerIsFreeEvent.Reset();                   // CriticalSect
                resultDataMutex.ReleaseMutex(); ;                // CriticalSect
                newResultEvent.Set();

                //mainForm.Invoke(delegateDisplay);
                mainForm.Dispatcher.Invoke(delegateDisplay);
                if (delegatedStopEvent.WaitOne(0, true)) break;

            }
            // --------  RESET/CLOSE ALL HANDLES  ---------
            mainForm.threadAcq.Join();
            //mainForm.Invoke(delegateControlReset);
            mainForm.Dispatcher.Invoke(delegateControlReset);
            reader.Dispose();

            newResultEvent.Reset();

            return;
}

注意到在WPF中Invoke被封装到Dispatcher中,所以委托的方式稍有不同。

7)运行界面


详细的源代码,见(Halcon)Multithreading

线程 2

猜你喜欢

转载自blog.csdn.net/huan_126/article/details/80323202
今日推荐