(转)Kinect背景移除支持多人

原文:http://blogs.msdn.com/b/k4wdev/archive/2013/10/22/using-kinect-background-removal-with-multiple-users.aspx?utm_source=tuicool

Introduction: Background Removal in Kinect for Windows

The 1.8 release of the Kinect for Windows Developer Toolkit includes a component for isolating a user from the background of the scene. The component is called the BackgroundRemovedColorStream. This capability has many possible uses, such as simulating chroma-key or “green-screen” replacement of the background – without needing to use an actual green screen; compositing a person’s image into a virtual environment; or simply blurring out the background, so that video conference participants can’t see how messy your office really is.

BackgroundRemovalBasics

To use this feature in an application, you create the BackgroundRemovedColorStream, and then feed it each incoming color, depth, and skeleton frame when they are delivered by your Kinect for Windows sensor. You also specify which user you want to isolate, using their skeleton tracking ID. The BackgroundRemovedColorStream produces a sequence of color frames, in BGRA (blue/green/red/alpha) format. These frames are identical in content to the original color frames from the sensor, except that the alpha channel is used to distinguish foreground pixels from background pixels. Pixels that the background removal algorithm considers part of the background will have an alpha value of 0 (fully transparent), while foreground pixels will have their alpha at 255 (fully opaque). The foreground region is given a smoother edge by using intermediate alpha values (between 0 and 255) for a “feathering” effect. This image format makes it easy to combine the background-removed frames with other images in your application.

As a developer, you get the choice of which user you want in the foreground. The BackgroundRemovalBasics-WPF samplehas some simple logic that selects the user nearest the sensor, and then continues to track the same user until they are no longer visible in the scene.

private void ChooseSkeleton()
{
var isTrackedSkeltonVisible = false;
var nearestDistance = float.MaxValue;
var nearestSkeleton = 0;
foreach (var skel in this.skeletons)
    {
if (null == skel)
        {
continue;
        }
if (skel.TrackingState != SkeletonTrackingState.Tracked)
        {
continue;
        }
if (skel.TrackingId == this.currentlyTrackedSkeletonId)
        {
            isTrackedSkeltonVisible = true;
break;
        }
if (skel.Position.Z < nearestDistance)
        {
            nearestDistance = skel.Position.Z;
            nearestSkeleton = skel.TrackingId;
        }
    }
if (!isTrackedSkeltonVisible && nearestSkeleton != 0)
    {
this.backgroundRemovedColorStream.SetTrackedPlayer(nearestSkeleton);
this.currentlyTrackedSkeletonId = nearestSkeleton;
    }
}

Wait, only one person?

If you wanted to select more than one person from the scene to appear in the foreground, it would seem that you’re out of luck, because the BackgroundRemovedColorStream’s SetTrackedPlayer method accepts only one tracking ID. But you can work around this limitation by running two separate instances of the stream, and sending each one a different tracking ID. Each of these streams will produce a separate color image, containing one of the users. These images can then be combined into a single image, or used separately, depending on your application’s needs.

Wait, only two people?

In the most straightforward implementation of the multiple stream approach, you’d be limited to tracking just two people, due to an inherent limitation in the skeleton tracking capability of Kinect for Windows. Only two skeletons at a time can be tracked with full joint-level fidelity. The joint positions are required by the background removal implementation in order to perform its job accurately.

However, there is an additional trick we can apply, to escape the two-skeleton limit. This trick relies on an assumption that the people in the scene will not be moving at extremely high velocities (generally a safe bet). If a particular skeleton is not fully tracked for a frame or two, we can instead reuse the most recent frame in which that skeleton actually was fully tracked. Since the skeleton tracking API lets us choose which two skeletons to track at full fidelity, we can choose a different pair of skeletons each frame, cycling through up to six skeletons we wish to track, over three successive frames.

Each additional instance of BackgroundRemovedColor stream will place increased demands on CPU and memory. Depending on your own application’s needs and your hardware configuration, you may need to dial back the number of simultaneous users you can process in this way.

Wait, only six people?

Demanding, aren’t we? Sorry, the Kinect for Windows skeleton stream can monitor at most six people simultaneously (two at full fidelity, and four at lower fidelity). This is a hard limit.

Introducing a multi-user background removal sample

We’ve created a new sample application, called BackgroundRemovalMultiUser-WPF, to demonstrate how to use the technique described above to perform background removal on up to six people. We started with the code from the BackgroundRemovalBasics-WPF sample, and changed it to support multiple streams, one per user. The output from each stream is then overlaid on the backdrop image.

BackgroundRemovalMultiUser

Factoring the code: TrackableUser

The largest change to the original sample was refactoring the application code that interacts the BackgroundRemovedColorStream, so that we can have multiple copies of it running simultaneously. This code, in the new sample, resides in a new class named TrackableUser. Let’s take a brief tour of the interesting parts of this class.

The application can instruct TrackableUser to track a specific user by setting the TrackingId property appropriately.

public int TrackingId
{
get
    {
return this.trackingId;
    }
set
    {
if (value != this.trackingId)
        {
            if (null != this.backgroundRemovedColorStream)
            {
if (InvalidTrackingId != value)
                {
this.backgroundRemovedColorStream.SetTrackedPlayer(value);
this.Timestamp = DateTime.UtcNow;
                }     
else
                {
// Hide the last frame that was received for this user.
this.imageControl.Visibility = Visibility.Hidden;     
this.Timestamp = DateTime.MinValue;
                }     
            }
this.trackingId = value;
        }
    }
}

The Timestamp property indicates when the TrackingId was most recently set to a valid value. We’ll see later how this property is used by the sample application’s user-selection logic.

public DateTime Timestamp { get; private set; }

Whenever the application is notified that the default Kinect sensor has changed (at startup time, or when the hardware is plugged in or unplugged), it passes this information along to each TrackableUser by calling OnKinectSensorChanged. The TrackableUser, in turn, sets up or tears down its BackgroundRemovedColorStream accordingly.

public void OnKinectSensorChanged(KinectSensor oldSensor, KinectSensor newSensor)
{
    if (null != oldSensor)
    {
// Remove sensor frame event handler.
        oldSensor.AllFramesReady -= this.SensorAllFramesReady;
// Tear down the BackgroundRemovedColorStream for this user.
this.backgroundRemovedColorStream.BackgroundRemovedFrameReady -=
this.BackgroundRemovedFrameReadyHandler;
this.backgroundRemovedColorStream.Dispose();
this.backgroundRemovedColorStream = null;
this.TrackingId = InvalidTrackingId;
    }
this.sensor = newSensor;
if (null != newSensor)
    {
// Setup a new BackgroundRemovedColorStream for this user.
this.backgroundRemovedColorStream = new BackgroundRemovedColorStream(newSensor);
this.backgroundRemovedColorStream.BackgroundRemovedFrameReady +=
this.BackgroundRemovedFrameReadyHandler;
this.backgroundRemovedColorStream.Enable(
            newSensor.ColorStream.Format,
            newSensor.DepthStream.Format);
// Add an event handler to be called when there is new frame data from the sensor.
        newSensor.AllFramesReady += this.SensorAllFramesReady;
    }
}

Each time the Kinect sensor produces a matched set of depth, color, and skeleton frames, we forward each frame’s data along to the BackgroundRemovedColorStream.

private void SensorAllFramesReady(object sender, AllFramesReadyEventArgs e)
{
    ...
if (this.IsTracked)
        {
using (var depthFrame = e.OpenDepthImageFrame())
            {     
if (null != depthFrame)
                {
// Process depth data for background removal.
this.backgroundRemovedColorStream.ProcessDepth(
                         depthFrame.GetRawPixelData(),
                         depthFrame.Timestamp);
                }
            }
using (var colorFrame = e.OpenColorImageFrame())     
            {     
if (null != colorFrame)     
                {
// Process color data for background removal.
this.backgroundRemovedColorStream.ProcessColor(
                        colorFrame.GetRawPixelData(),
                        colorFrame.Timestamp);     
                }
            }
using (var skeletonFrame = e.OpenSkeletonFrame())
            {
if (null != skeletonFrame)
                {
// Save skeleton frame data for subsequent processing.
                    CopyDataFromSkeletonFrame(skeletonFrame);
// Locate the most recent data in which this user was fully tracked.
bool isUserPresent = UpdateTrackedSkeletonsArray();
// If we have an array in which this user is fully tracked,
// process the skeleton data for background removal.
if (isUserPresent && null != this.skeletonsTracked)
                    {
this.backgroundRemovedColorStream.ProcessSkeleton(
this.skeletonsTracked,
                            skeletonFrame.Timestamp);
                     }
                }
            }
        }
    ...
}

The UpdateTrackedSkeletonsArray method implements the logic to reuse skeleton data from an older frame when the newest frame contains the user’s skeleton, but not in a fully-tracked state. It also informs the caller whether the user with the requested tracking ID is still present in the scene.

private bool UpdateTrackedSkeletonsArray()
{
// Determine if this user is still present in the scene.
bool isUserPresent = false;
foreach (var skeleton in this.skeletonsNew)
    {
if (skeleton.TrackingId == this.TrackingId)
         {
            isUserPresent = true;
if (skeleton.TrackingState == SkeletonTrackingState.Tracked)
             {
// User is fully tracked: save the new array of skeletons,
// and recycle the old saved array for reuse next time.
var temp = this.skeletonsTracked;
this.skeletonsTracked = this.skeletonsNew;
this.skeletonsNew = temp;
            }
break;
        }
    }
if (!isUserPresent)
    {
// User has disappeared; stop trying to track.
this.TrackingId = TrackableUser.InvalidTrackingId;
    }
return isUserPresent;
}

Whenever the BackgroundRemovedColorStream produces a frame, we copy its BGRA data to the bitmap that is the underlying Source for an Image element in the MainWindow. This causes the updated frame to appear within the application’s window, overlaid on the background image.

private void BackgroundRemovedFrameReadyHandler(
object sender,
BackgroundRemovedColorFrameReadyEventArgs e)
{
using (var backgroundRemovedFrame = e.OpenBackgroundRemovedColorFrame())
    {
if (null != backgroundRemovedFrame && this.IsTracked)
         {
int width = backgroundRemovedFrame.Width;
int height = backgroundRemovedFrame.Height;
WriteableBitmap foregroundBitmap =
this.imageControl.Source as WriteableBitmap;
// If necessary, allocate new bitmap. Set it as the source of the Image
// control.
if (null == foregroundBitmap ||
                foregroundBitmap.PixelWidth != width ||
                foregroundBitmap.PixelHeight != height)
            {
                foregroundBitmap = new WriteableBitmap(
                    width,     
                    height,
                    96.0,
                    96.0,     
PixelFormats.Bgra32,
null);
this.imageControl.Source = foregroundBitmap;
            }
// Write the pixel data into our bitmap.
            foregroundBitmap.WritePixels(
new Int32Rect(0, 0, width, height),
                backgroundRemovedFrame.GetRawPixelData(),
                width * sizeof(uint),
                0);
// A frame has been delivered; ensure that it is visible.
this.imageControl.Visibility = Visibility.Visible;
        }
    }
}

Limiting the number of users to track

As mentioned earlier, the maximum number of trackable users may have a practical limit, depending on your hardware. To specify the limit, we define a constant in the MainWindow class:

private const int MaxUsers = 6;

You can modify this constant to have any value from 2 to 6. (Values larger than 6 are not useful, as Kinect for Windows does not track more than 6 users.)

Selecting users to track: The User View

We want to provide a convenient way to choose which users will be tracked for background removal. To do this, we present a view of the detected users in a small inset. By clicking on the users displayed in this inset, we can select which of those users are associated with our TrackableUser objects, causing them to be included in the foreground.

UserView

We update the user view each time a depth frame is received by the sample’s main window.

private void UpdateUserView(DepthImageFrame depthFrame)
{
    ...
// Store the depth data.
    depthFrame.CopyDepthImagePixelDataTo(this.depthData);     
    ...
// Write the per-user colors into the user view bitmap, one pixel at a time.
this.userViewBitmap.Lock();
unsafe
    {
uint* userViewBits = (uint*)this.userViewBitmap.BackBuffer;
fixed (uint* userColors = &this.userColors[0])
        {     
// Walk through each pixel in the depth data.
fixed (DepthImagePixel* depthData = &this.depthData[0])     
            {
                DepthImagePixel* depthPixel = depthData;
                DepthImagePixel* depthPixelEnd = depthPixel + this.depthData.Length;
while (depthPixel < depthPixelEnd)
                {
// Lookup a pixel color based on the player index.
// Store the color in the user view bitmap's buffer.
                    *(userViewBits++) = *(userColors + (depthPixel++)->PlayerIndex);
                }
            }
        }
    }
this.userViewBitmap.AddDirtyRect(new Int32Rect(0, 0, width, height));
this.userViewBitmap.Unlock();
}

This code fills the user view bitmap with solid-colored regions representing each of the detected users, as distinguished by the value of the PlayerIndex field at each pixel in the depth frame.

The main window responds to a mouse click within the user view by locating the corresponding pixel in the most recent depth frame, and using its PlayerIndex to look up the user’s TrackingId in the most recent skeleton data. The TrackingID is passed along to the ToggleUserTracking method, which will attempt to toggle the tracking of that TrackingID between the tracked and untracked states.

private void UserViewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// Determine which pixel in the depth image was clicked.
    Point p = e.GetPosition(this.UserView);
int depthX =
        (int)(p.X * this.userViewBitmap.PixelWidth / this.UserView.ActualWidth);
int depthY =
        (int)(p.Y * this.userViewBitmap.PixelHeight / this.UserView.ActualHeight);
int pixelIndex = (depthY * this.userViewBitmap.PixelWidth) + depthX;
if (pixelIndex >= 0 && pixelIndex < this.depthData.Length)
    {
// Find the player index in the depth image. If non-zero, toggle background
// removal for the corresponding user.
short playerIndex = this.depthData[pixelIndex].PlayerIndex;
if (playerIndex > 0)
        {     
// playerIndex is 1-based, skeletons array is 0-based, so subtract 1.
this.ToggleUserTracking(this.skeletons[playerIndex - 1].TrackingId);
        }
    }
}

Picking which users will be tracked

When MaxUsers is less than 6, we need some logic to handle a click on an untracked user, and we are already tracking the maximum number of users. We choose to stop tracking the user who was tracked earliest (based on timestamp), and start tracking the newly chosen user immediately. This logic is implemented in ToggleUserTracking.

private void ToggleUserTracking(int trackingId)
{
if (TrackableUser.InvalidTrackingId != trackingId)
    {
        DateTime minTimestamp = DateTime.MaxValue;
TrackableUser trackedUser = null;
TrackableUser staleUser = null;
// Attempt to find a TrackableUser with a matching TrackingId.
foreach (var user in this.trackableUsers)
        {
if (user.TrackingId == trackingId)
            {
// Yes, this TrackableUser has a matching TrackingId.
                trackedUser = user;
            }
// Find the "stale" user (the trackable user with the earliest timestamp).
if (user.Timestamp < minTimestamp)
            {     
                staleUser = user;
                minTimestamp = user.Timestamp;
            }
        }
if (null != trackedUser)
        {
// User is being tracked: toggle to not tracked.
            trackedUser.TrackingId = TrackableUser.InvalidTrackingId;
        }
else
        {     
// User is not currently being tracked: start tracking, by reusing
// the "stale" trackable user.
            staleUser.TrackingId = trackingId;
        }
    }
}

Once we’ve determined which users will be tracked by the TrackableUser objects, we need to ensure that those users are being targeted for tracking by the skeleton stream on a regular basis (at least once every three frames). UpdateChosenSkeletons implements this using a round-robin scheme.

private void UpdateChosenSkeletons()
{
KinectSensor sensor = this.sensorChooser.Kinect;
if (null != sensor)
    {
// Choose which of the users will be tracked in the next frame.
int trackedUserCount = 0;
for (int i = 0; i < MaxUsers && trackedUserCount < this.trackingIds.Length; ++i)
         {
// Get the trackable user for consideration.
var trackableUser = this.trackableUsers[this.nextUserIndex];
if (trackableUser.IsTracked)
            {
// If this user is currently being tracked, copy its TrackingId to the
// array of chosen users.
this.trackingIds[trackedUserCount++] = trackableUser.TrackingId;
            }
// Update the index for the next user to be considered.
this.nextUserIndex = (this.nextUserIndex + 1) % MaxUsers;
        }     
// Fill any unused slots with InvalidTrackingId.
for (int i = trackedUserCount; i < this.trackingIds.Length; ++i)
        {
this.trackingIds[i] = TrackableUser.InvalidTrackingId;
        }
// Pass the chosen tracking IDs to the skeleton stream.
        sensor.SkeletonStream.ChooseSkeletons(this.trackingIds[0], this.trackingIds[1]);
    }
}

Combining multiple foreground images

Now that we can have multiple instances of TrackableUser, each producing a background-removed image of a user, we need to combine those images on-screen. We do this by creating multiple overlapping Image elements (one per trackable user), each parented by the MaskedColorImages element, which itself is a sibling of the Backdrop element. Wherever the background has been removed from each image, the backdrop image will show through.

As each image is created, we associate it with its own TrackableUser.

public MainWindow()
{
    ...
// Create one Image control per trackable user.
for (int i = 0; i < MaxUsers; ++i)
    {
Image image = new Image();
this.MaskedColorImages.Children.Add(image);
this.trackableUsers[i] = new TrackableUser(image);
    }
}

To capture and save a snapshot of the current composited image, we create two VisualBrush objects, one for the Backdrop, and one for MaskedColorImages. We draw rectangles with each of these brushes, into a bitmap, and then write the bitmap to a file.

private void ButtonScreenshotClick(object sender, RoutedEventArgs e)
{
    ...
var dv = new DrawingVisual();
using (var dc = dv.RenderOpen())
    {
// Render the backdrop.
var backdropBrush = new VisualBrush(Backdrop);     
        dc.DrawRectangle(
            backdropBrush,     
null,
new Rect(new Point(), new Size(colorWidth, colorHeight)));
// Render the foreground.
var colorBrush = new VisualBrush(MaskedColorImages);     
        dc.DrawRectangle(
            colorBrush,
null,
new Rect(new Point(), new Size(colorWidth, colorHeight)));
    }
    renderBitmap.Render(dv);
    ...
}

Summary

While the BackgroundRemovedColorStream is limited to tracking only one user at a time, the new BackgroundRemovalMultiUser-WPF sample demonstrates that you can run multiple stream instances to track up to six users simultaneously. When using this technique, you should consider – and measure – the increased resource demands (CPU and memory) that the additional background removal streams will have, and determine for yourself how many streams your configuration can handle.

We hope that this sample opens up new possibilities for using background removal in your own applications.

John Elsbree
Principal Software Development Engineer
Kinect for Windows

转载于:https://www.cnblogs.com/leven20061001/p/3524462.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/493509.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

德国汉堡科学院院士张建伟:信息物理系统驱动智能未来

来源&#xff1a;OFweek工控网随着第四次工业革命的到来&#xff0c;信息技术&#xff08;IT&#xff09;和运营技术&#xff08;OT&#xff09;的融合成为新趋势&#xff0c;工厂开始进入数字化转型阶段&#xff0c;而德国“工业4.0”战略给全球制造业发展带来启示&#xff0c…

两层卷积网络实现手写字母的识别(基于tensorflow)

可和这篇文章对比&#xff0c;https://blog.csdn.net/fanzonghao/article/details/81489049&#xff0c;数据集来源代码和链接一样。 import tensorflow as tf import numpy as np import matplotlib.pyplot as plt import read_pickle_datasettrain_dataset,train_label,vali…

焦李成教授谈深度神经网络发展历程

来源&#xff1a;西电人工智能学院摘要&#xff1a;焦李成教授谈深度神经网络发展历程2018年11月18日下午&#xff0c;计算机科学与技术学部主任、人工智能学院焦李成教授在成都参加了由中国人工智能学会主办的人工智能大讲堂并做特邀报告&#xff0c;焦李成教授在报告中回顾了…

KNN实现CIFAR-10数据集识别

cs231n链接&#xff1a;http://cs231n.github.io/linear-classify/&#xff0c; 训练集链接&#xff1a;https://download.csdn.net/download/fanzonghao/10592049 KNN缺点&#xff1a;每个测试样本都要循环一遍训练样本。 该数据集由5个data_batch和一个test_batch构成&…

近期苹果、Facebook等科技巨头股价缘何不断下跌?

来源&#xff1a;资本实验室近期&#xff0c;FAANG(Facebook、亚马逊、苹果、Netflix、谷歌)等科技巨头股价都出现了不同程度的下跌&#xff0c;而美国科技股整体的持续大跌&#xff0c;更是引发了全球股市振荡。其中&#xff0c;亚马逊在今年9月初达曾达到1万亿美元市值&#…

概率论基础知识各种分布

离散分布&#xff1a;伯努力分布&#xff0c;二项分布&#xff0c;possion分布 一&#xff0c;伯努力分布 #执硬币 x_arrnp.array([0,1]) #x为1的概率 p0.7 #0 1分布 #由PMF生成对应的概率 离散事件 pr_arrstats.bernoulli.pmf(x_arr,p) plt.plot(x_arr,pr_arr,markero,lines…

AI 芯片和传统芯片的区别

来源&#xff1a;内容来自「知乎汪鹏 」所谓的AI芯片&#xff0c;一般是指针对AI算法的ASIC&#xff08;专用芯片&#xff09;。传统的CPU、GPU都可以拿来执行AI算法&#xff0c;但是速度慢&#xff0c;性能低&#xff0c;无法实际商用。比如&#xff0c;自动驾驶需要识别道路行…

三层神经网络实现手写数字的识别(基于tensorflow)

数据集链接&#xff1a;https://download.csdn.net/download/fanzonghao/10598333 from tensorflow.examples.tutorials.mnist import input_data mnist input_data.read_data_sets("./mnist/", one_hotTrue)import tensorflow as tf# Parameters learning_rate 0…

鼠标终将消失,未来我们有哪些人机交互方式?

来源&#xff1a;资本实验室在人类发明史上&#xff0c;诞生了无数的英雄。他们的发明往往从一项前沿技术到家喻户晓、无处不在&#xff0c;但他们自己却又鲜为人知&#xff0c;美国发明家道格拉斯恩格尔巴特就是其中的代表。20世纪60年代&#xff0c;道格拉斯恩格尔巴特发明了…

两层卷积网络实现手写数字的识别(基于tensorflow)

可和这篇文章对比&#xff1a;https://blog.csdn.net/fanzonghao/article/details/81603367 # coding: utf-8 # ## MNIST数据集from __future__ import division, print_function, absolute_importimport tensorflow as tf# Import MNIST data&#xff0c;MNIST数据集导入 fro…

光波导总结资料

1、写出光波导中的麦克斯韦方程&#xff0c;并把光场分解为纵向分量与横向分量&#xff0c;求出混合模式HE与EH模式的横向电场强度与横向磁场强度的点积&#xff08;用纵向分量表示&#xff09;&#xff08;需要有推导过程&#xff09; 解&#xff1a;在线性、各向同性且时不变…

德国再出颠覆性发明,这次要安排我们的快递

来源&#xff1a;最黑科技摘要&#xff1a;如果用一句话来形容德国的工业设计&#xff0c;我能想到的就是&#xff1a;“母牛坐电锯——锯牛逼"&#xff0c;小编已经不止一次把它吹得五光十色斗转星移~但你可能不知道&#xff0c;这个工业强国在2013年还提出了一个著名的发…

C++中用frugally-deep调用keras的模型并进行预测

1、背景 Python语言中的Keras库搭建深度学习模型非常便捷&#xff0c;但有时需要在 C 中调用训练好的模型&#xff0c;得到测试集的结果。比如将模型部署于FPGA&#xff0c;中间的一个步骤则需要用C构建模型。但 Keras库没有提供 C API&#xff0c;其中一种解决方法是使用 Ten…

简单的线性回归实现模型的存储和读取

和这篇文章对比https://blog.csdn.net/fanzonghao/article/details/81023730 不希望重复定义图上的运算&#xff0c;也就是在模型恢复过程中&#xff0c;不想sess.run(init)首先看路径 lineRegulation_model.py定义线性回归类&#xff1a; import tensorflow as tf "&qu…

MIT重新发明飞机:无需燃料,每秒万米喷射带你上天 | Nature封面

来源&#xff1a;量子位这不是科幻小说&#xff0c;离子引擎飞机真的被造出来了&#xff01;“曲率引擎”、“离子引擎”等等激动人心的科幻名词&#xff0c;正在走进现实。最近MIT又重新发明了飞机&#xff0c;实验成果登上了《自然》杂志封面。这架飞机翼展5米&#xff0c;总…

unet实现区域分割

https://github.com/zonghaofan/pig-seg/tree/master/disk_segmentation 网络架构&#xff1a; # coding:utf-8 import tensorflow as tf import cv2 import numpy as np import matplotlib.pyplot as pltimg cv2.imread(./data/test.png)# cv2.imshow(1.jpg,img) # cv2.wait…

数字图像处理 实验一 图像的基本运算

实验一 图像的基本运算 一、实验目的 &#xff08;1&#xff09;掌握点运算和代数运算的算法实现和概念 &#xff08;2&#xff09;掌握和几何运算的算法实现和概念 &#xff08;2&#xff09;掌握灰度变换和几何变换的基本方法 &#xff08;3&#xff09;理解图像灰度直方图的…

2018世界人工智能蓝皮书:看中国到底有多强!【附下载】| 智东西内参

来源&#xff1a;智东西人工智能是引领未来的战略性高科技&#xff0c;作为新一轮产业变革的核心驱动力&#xff0c;催生新技术、新产品、新产业、新模式&#xff0c;引发经济结构重大变革&#xff0c;深刻改变人类生产生活方式和思维模式&#xff0c;实现社会生产力的整体跃升…

tensorflow(GPU)使用

一&#xff0c;直接指定GPU: tf.ConfigProto一般用在创建session的时候。用来对session进行参数配置 with tf.Session(config tf.ConfigProto(...),...) #tf.ConfigProto()的参数 log_device_placementTrue : 是否打印设备分配日志 allow_soft_placementTrue &#xff1a; 如…

数字图像处理实验二 图像变换

一、实验目的 &#xff08;1&#xff09;了解图像变换的意义和手段。 &#xff08;2&#xff09;熟悉傅立叶变换的基本性质。 &#xff08;3&#xff09;通过实验了解二维频谱的分布特点。 &#xff08;4&#xff09;了解余弦变换或Walsh&#xff0d;Hadamard变换 二、实验内容…