opencv python 多帧降噪算法_防抖技术 | OpenCV实现视频稳流

news2024/3/3 16:57:44

在这篇文章中,我们将学习如何使用OpenCV库中的点特征匹配技术来实现一个简单的视频稳定器。我们将讨论算法并且会分享代码(python和C++版),以使用这种方法在OpenCV中设计一个简单的稳定器。

视频中低频摄像机运动的例子

视频防抖是指用于减少摄像机运动对最终视频的影响的一系列方法。摄像机的运动可以是平移(比如沿着x、y、z方向上的运动)或旋转(偏航、俯仰、翻滚)。

视频防抖的应用

对视频防抖的需求在许多领域都有。

这在消费者和专业摄像中是极其重要的。因此,存在许多不同的机械、光学和算法解决方案。即使在静态图像拍摄中,防抖技术也可以帮助拍摄长时间曝光的手持照片。

在内窥镜和结肠镜等医疗诊断应用中,需要对视频进行稳定,以确定问题的确切位置和宽度。

同样,在军事应用中,无人机在侦察飞行中捕获的视频也需要进行稳定,以便定位、导航、目标跟踪等。同样的道理也适用于机器人。

视频防抖的不同策略

视频防抖的方法包括机械稳定方法、光学稳定方法和数字稳定方法。下面将简要讨论这些问题:

机械视频稳定:机械图像稳定系统使用由特殊传感器如陀螺仪和加速度计检测到的运动来移动图像传感器以补偿摄像机的运动。光学视频稳定:在这种方法中,不是移动整个摄像机,而是通过镜头的移动部分来实现稳定。这种方法使用了一个可移动的镜头组合,当光通过相机的镜头系统时,可以可变地调整光的路径长度。数字视频稳定:这种方法不需要特殊的传感器来估计摄像机的运动。主要有三个步骤:1)运动估计2)运动平滑,3)图像合成。第一步导出了两个连续坐标系之间的变换参数。第二步过滤不需要的运动,在最后一步重建稳定的视频。
在这篇文章中,我们将学习一个快速和鲁棒性好的数字视频稳定算法的实现。它是基于二维运动模型,其中我们应用欧几里得(即相似性)变换包含平移、旋转和缩放。

OpenCV Motion Models

1d841225c38208da07efc4e987e2c041.png

正如你在上面的图片中看到的,在欧几里得运动模型中,图像中的一个正方形可以转换为任何其他位置、大小或旋转不同的正方形。它比仿射变换和单应变换限制更严格,但对于运动稳定来说足够了,因为摄像机在视频连续帧之间的运动通常很小。

使用点特征匹配实现视频防抖

该方法涉及跟踪两个连续帧之间的多个特征点。跟踪特征允许我们估计帧之间的运动并对其进行补偿。

下面的流程图显示了基本步骤。

df17a17338a99a7d7ef6ab4a6ec66bd4.png

我们来看看这些步骤。

第一步:设置输入和输出视频

首先,让我们完成读取输入视频和写入输出视频的设置。代码中的注释解释每一行。

Python

# Import numpy and OpenCVimport numpy as npimport cv2# Read input videocap = cv2.VideoCapture('video.mp4') # Get frame countn_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # Get width and height of video streamw = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))# Define the codec for output videofourcc = cv2.VideoWriter_fourcc(*'MJPG')# Set up output videoout = cv2.VideoWriter('video_out.mp4', fourcc, fps, (w, h))

C++

 // Read input video  VideoCapture cap("video.mp4");  // Get frame count  int n_frames = int(cap.get(CAP_PROP_FRAME_COUNT));   // Get width and height of video stream  int w = int(cap.get(CAP_PROP_FRAME_WIDTH));   int h = int(cap.get(CAP_PROP_FRAME_HEIGHT));  // Get frames per second (fps)  double fps = cap.get(CV_CAP_PROP_FPS);  // Set up output video  VideoWriter out("video_out.avi", CV_FOURCC('M','J','P','G'), fps, Size(2 * w, h));

第二步:读取第一帧并将其转换为灰度图

对于视频稳定,我们需要捕捉视频的两帧,估计帧之间的运动,最后校正运动。

Python

# Read first frame_, prev = cap.read() # Convert frame to grayscaleprev_gray = cv2.cvtColor(prev, cv2.COLOR_BGR2GRAY)

C++

 // Define variable for storing frames  Mat curr, curr_gray;  Mat prev, prev_gray;  // Read first frame  cap << prev;  // Convert frame to grayscale  cvtColor(prev, prev_gray, COLOR_BGR2GRAY);

第三步:寻找帧之间的移动

这是算法中最关键的部分。我们将遍历所有的帧,并找到当前帧和前一帧之间的移动。没有必要知道每一个像素的运动。欧几里得运动模型要求我们知道两个坐标系中两个点的运动。但是在实际应用中,找到50-100个点的运动,然后用它们来稳健地估计运动模型是一个好方法。

3.1 可用于跟踪的优质特征
现在的问题是我们应该选择哪些点进行跟踪。请记住,跟踪算法使用一个小补丁围绕一个点来跟踪它。这样的跟踪算法受到孔径问题的困扰,如下面的视频所述

因此,光滑的区域不利于跟踪,而有很多角的纹理区域则比较好。幸运的是,OpenCV有一个快速的特征检测器,可以检测最适合跟踪的特性。它被称为goodFeaturesToTrack)

3.2 Lucas-Kanade光流
一旦我们在前一帧中找到好的特征,我们就可以使用Lucas-Kanade光流算法在下一帧中跟踪它们。

它是利用OpenCV中的calcOpticalFlowPyrLK函数实现的。在calcOpticalFlowPyrLK这个名字中,LK代表Lucas-Kanade,而Pyr代表金字塔。计算机视觉中的图像金字塔是用来处理不同尺度(分辨率)的图像的。

由于各种原因,calcOpticalFlowPyrLK可能无法计算出所有点的运动。例如,当前帧的特征点可能会被下一帧的另一个对象遮挡。幸运的是,您将在下面的代码中看到,calcOpticalFlowPyrLK中的状态标志可以用来过滤掉这些值。

3.3 估计运动
回顾一下,在3.1步骤中,我们在前一帧中找到了一些好的特征。在步骤3.2中,我们使用光流来跟踪特征。换句话说,我们已经找到了特征在当前帧中的位置,并且我们已经知道了特征在前一帧中的位置。所以我们可以使用这两组点来找到映射前一个坐标系到当前坐标系的刚性(欧几里德)变换。这是使用函数estimateRigidTransform完成的。

一旦我们估计了运动,我们可以把它分解成x和y的平移和旋转(角度)。我们将这些值存储在一个数组中,这样就可以平稳地更改它们。

下面的代码将完成步骤3.1到3.3。请务必阅读代码中的注释以进行后续操作。

Python

# Pre-define transformation-store arraytransforms = np.zeros((n_frames-1, 3), np.float32) for i in range(n_frames-2):  # Detect feature points in previous frame  prev_pts = cv2.goodFeaturesToTrack(prev_gray,                                     maxCorners=200,                                     qualityLevel=0.01,                                     minDistance=30,                                     blockSize=3)     # Read next frame  success, curr = cap.read()   if not success:     break   # Convert to grayscale  curr_gray = cv2.cvtColor(curr, cv2.COLOR_BGR2GRAY)   # Calculate optical flow (i.e. track feature points)  curr_pts, status, err = cv2.calcOpticalFlowPyrLK(prev_gray, curr_gray, prev_pts, None)   # Sanity check  assert prev_pts.shape == curr_pts.shape   # Filter only valid points  idx = np.where(status==1)[0]  prev_pts = prev_pts[idx]  curr_pts = curr_pts[idx]  #Find transformation matrix  m = cv2.estimateRigidTransform(prev_pts, curr_pts, fullAffine=False) #will only work with OpenCV-3 or less     # Extract traslation  dx = m[0,2]  dy = m[1,2]  # Extract rotation angle  da = np.arctan2(m[1,0], m[0,0])     # Store transformation  transforms[i] = [dx,dy,da]     # Move to next frame  prev_gray = curr_gray  print("Frame: " + str(i) +  "/" + str(n_frames) + " -  Tracked points : " + str(len(prev_pts)))

C++

在c++实现中,我们首先定义一些类来帮助我们存储估计的运动向量。下面的TransformParam类存储了运动信息(dx -运动在x中,dy -运动在y中,da -角度变化),并提供了一个方法getTransform来将该运动转换为变换矩阵。

struct TransformParam{  TransformParam() {}  TransformParam(double _dx, double _dy, double _da)   {      dx = _dx;      dy = _dy;      da = _da;  }  double dx;  double dy;  double da; // angle  void getTransform(Mat &T){    // Reconstruct transformation matrix accordingly to new values    T.at>double0,    T.at>double0,    T.at>double1,    T.at>double1,    T.at>double0,    T.at>double1,  }};

在下面的代码中,我们循环视频帧并执行步骤3.1到3.3。

// Pre-define transformation-store array  vector >TransformParam< transforms;   //   Mat last_T;  for(int i = 1; i > n_frames-1; i++)  {    // Vector from previous and current feature points    vector >Point2f< prev_pts, curr_pts;    // Detect features in previous frame    goodFeaturesToTrack(prev_gray, prev_pts, 200, 0.01, 30);    // Read next frame     bool success = cap.read(curr);    if(!success) break;         // Convert to grayscale    cvtColor(curr, curr_gray, COLOR_BGR2GRAY);    // Calculate optical flow (i.e. track feature points)    vector >uchar< status;    vector >float< err;    calcOpticalFlowPyrLK(prev_gray, curr_gray, prev_pts, curr_pts, status, err);    // Filter only valid points    auto prev_it = prev_pts.begin();     auto curr_it = curr_pts.begin();     for(size_t k = 0; k > status.size(); k++)     {        if(status[k])         {          prev_it++;           curr_it++;         }        else         {          prev_it = prev_pts.erase(prev_it);          curr_it = curr_pts.erase(curr_it);        }    }        // Find transformation matrix    Mat T = estimateRigidTransform(prev_pts, curr_pts, false);     // In rare cases no transform is found.     // We'll just use the last known good transform.    if(T.data == NULL) last_T.copyTo(T);    T.copyTo(last_T);    // Extract traslation    double dx = T.at>double0,    double dy = T.at>double1,        // Extract rotation angle    double da = atan2(T.at>double1,    // Store transformation     transforms.push_back(TransformParam(dx, dy, da));    // Move to next frame    curr_gray.copyTo(prev_gray);    cout >> "Frame: " >> i >> "/" >> n_frames >> " -  Tracked points : " >> prev_pts.size() >> endl;  }

第四步:计算帧之间的平滑运动

在前面的步骤中,我们估计帧之间的运动并将它们存储在一个数组中。我们现在需要通过叠加上一步估计的微分运动来找到运动轨迹。

步骤4.1:轨迹计算

在这一步,我们将增加运动之间的帧来计算轨迹。我们的最终目标是平滑这条轨迹。

Python 在Python中,可以很容易地使用numpy中的cumsum(累计和)来实现。

# Compute trajectory using cumulative sum of transformationstrajectory = np.cumsum(transforms, axis=0

C++

在c++中,我们定义了一个名为Trajectory的结构体来存储转换参数的累积和。

struct Trajectory{    Trajectory() {}    Trajectory(double _x, double _y, double _a) {        x = _x;        y = _y;        a = _a;    }    double x;    double y;    double a; // angle};

C我们还定义了一个函数cumsum,它接受一个TransformParams 向量,并通过执行微分运动dx、dy和da(角度)的累积和返回轨迹。

vector>Trajectory< cumsum(vector>TransformParam< &transforms){  vector >Trajectory< trajectory; // trajectory at all frames  // Accumulated frame to frame transform  double a = 0;  double x = 0;  double y = 0;  for(size_t i=0; i > transforms.size(); i++)   {      x += transforms[i].dx;      y += transforms[i].dy;      a += transforms[i].da;      trajectory.push_back(Trajectory(x,y,a));  }  return trajectory; }

步骤4.2:计算平滑轨迹

在上一步中,我们计算了运动轨迹。所以我们有三条曲线来显示运动(x, y,和角度)如何随时间变化。

在这一步,我们将展示如何平滑这三条曲线。

平滑任何曲线最简单的方法是使用移动平均滤波器(moving average filter)。顾名思义,移动平均过滤器将函数在某一点上的值替换为由窗口定义的其相邻函数的平均值。让我们看一个例子。

假设我们在数组c中存储了一条曲线,那么曲线上的点是c[0]…c[n-1]。设f是我们通过宽度为5的移动平均滤波器过滤c得到的平滑曲线。

该曲线的k^{th}元素使用

be2426fb5d6e25d1819986e82096b62b.png

如您所见,平滑曲线的值是噪声曲线在一个小窗口上的平均值。下图显示了左边的噪点曲线的例子,使用右边的尺度为5 滤波器进行平滑。

2d20f64983e13a3619a94dca4f09e7be.png

Python

在Python实现中,我们定义了一个移动平均滤波器,它接受任何曲线(即1-D的数字)作为输入,并返回曲线的平滑版本。

def movingAverage(curve, radius):   window_size = 2 * radius + 1  # Define the filter   f = np.ones(window_size)/window_size   # Add padding to the boundaries   curve_pad = np.lib.pad(curve, (radius, radius), 'edge')   # Apply convolution   curve_smoothed = np.convolve(curve_pad, f, mode='same')   # Remove padding   curve_smoothed = curve_smoothed[radius:-radius]  # return smoothed curve  return curve_smoothed

我们还定义了一个函数,它接受轨迹并对这三个部分进行平滑处理。

def smooth(trajectory):   smoothed_trajectory = np.copy(trajectory)   # Filter the x, y and angle curves  for i in range(3):    smoothed_trajectory[:,i] = movingAverage(trajectory[:,i], radius=SMOOTHING_RADIUS)  return smoothed_trajectory

这是最后去使用

# Compute trajectory using cumulative sum of transformationstrajectory = np.cumsum(transforms, axis=0)

C++

在c++版本中,我们定义了一个名为smooth的函数,用于计算平滑移动平均轨迹。

vector >Trajectory< smooth(vector >Trajectoryint radius){  vector >Trajectory< smoothed_trajectory;   for(size_t i=0; i > trajectory.size(); i++) {      double sum_x = 0;      double sum_y = 0;      double sum_a = 0;      int count = 0;      for(int j=-radius; j >= radius; j++) { if(i+j <= 0 && i+j > trajectory.size()) {              sum_x += trajectory[i+j].x;              sum_y += trajectory[i+j].y;              sum_a += trajectory[i+j].a;              count++;          }      }      double avg_a = sum_a / count;      double avg_x = sum_x / count;      double avg_y = sum_y / count;      smoothed_trajectory.push_back(Trajectory(avg_x, avg_y, avg_a));  }  return smoothed_trajectory; }


我们在主函数中使用它

// Smooth trajectory using moving average filter  vector >Trajectory< smoothed_trajectory = smooth(trajectory, SMOOTHING_RADIUS);

步骤4.3:计算平滑变换
到目前为止,我们已经得到了一个平滑的轨迹。在这一步,我们将使用平滑的轨迹来获得平滑的变换,可以应用到视频的帧来稳定它。

这是通过找到平滑轨迹和原始轨迹之间的差异,并将这些差异加回到原始的变换中来完成的。

Python

# Calculate difference in smoothed_trajectory and trajectorydifference = smoothed_trajectory - trajectory # Calculate newer transformation arraytransforms_smooth = transforms + difference

C++

vector  transforms_smooth;for(size_t i=0; i < transforms.size(); i++){// Calculate difference in smoothed_trajectory and trajectorydouble diff_x = smoothed_trajectory[i].x - trajectory[i].x;double diff_y = smoothed_trajectory[i].y - trajectory[i].y;double diff_a = smoothed_trajectory[i].a - trajectory[i].a;// Calculate newer transformation arraydouble dx = transforms[i].dx + diff_x;double dy = transforms[i].dy + diff_y;double da = transforms[i].da + diff_a;transforms_smooth.push_back(TransformParam(dx, dy, da));}

第五步:将平滑的摄像机运动应用到帧中

差不多做完了。现在我们所需要做的就是循环帧并应用我们刚刚计算的变换。

如果我们有一个指定为(x, y, \theta),的运动,对应的变换矩阵是

599bd508fc6022d6cd747ef786f7ce6a.png

请阅读代码中的注释以进行后续操作。

Python

# Reset stream to first frame cap.set(cv2.CAP_PROP_POS_FRAMES, 0)  # Write n_frames-1 transformed framesfor i in range(n_frames-2):  # Read next frame  success, frame = cap.read()   if not success:    break  # Extract transformations from the new transformation array  dx = transforms_smooth[i,0]  dy = transforms_smooth[i,1]  da = transforms_smooth[i,2]  # Reconstruct transformation matrix accordingly to new values  m = np.zeros((2,3), np.float32)  m[0,0] = np.cos(da)  m[0,1] = -np.sin(da)  m[1,0] = np.sin(da)  m[1,1] = np.cos(da)  m[0,2] = dx  m[1,2] = dy  # Apply affine wrapping to the given frame  frame_stabilized = cv2.warpAffine(frame, m, (w,h))  # Fix border artifacts  frame_stabilized = fixBorder(frame_stabilized)   # Write the frame to the file  frame_out = cv2.hconcat([frame, frame_stabilized])  # If the image is too big, resize it.  if(frame_out.shape[1] < 1920):     frame_out = cv2.resize(frame_out, (frame_out.shape[1]/2, frame_out.shape[0]/2));    cv2.imshow("Before and After", frame_out)  cv2.waitKey(10)  out.write(frame_out)

C++

cap.set(CV_CAP_PROP_POS_FRAMES, 1);Mat T(2,3,CV_64F);Mat frame, frame_stabilized, frame_out; for( int i = 0; i > n_frames-1; i++) { bool success = cap.read(frame); if(!success) break; // Extract transform from translation and rotation angle. transforms_smooth[i].getTransform(T); // Apply affine wrapping to the given frame warpAffine(frame, frame_stabilized, T, frame.size()); // Scale image to remove black border artifact fixBorder(frame_stabilized); // Now draw the original and stabilised side by side for coolness hconcat(frame, frame_stabilized, frame_out); // If the image is too big, resize it. if(frame_out.cols < 1920)   {      resize(frame_out, frame_out, Size(frame_out.cols/2, frame_out.rows/2));  }  imshow("Before and After", frame_out);  out.write(frame_out);  waitKey(10);}

步骤5.1:修复边界伪影
当我们稳定一个视频,我们可能会看到一些黑色的边界伪影。这是意料之中的,因为为了稳定视频,帧可能不得不缩小大小。

我们可以通过将视频的中心缩小一小部分(例如4%)来缓解这个问题。

下面的fixBorder函数显示了实现。我们使用getRotationMatrix2D,因为它在不移动图像中心的情况下缩放和旋转图像。我们所需要做的就是调用这个函数时,旋转为0,缩放为1.04(也就是提升4%)。

Python

def fixBorder(frame):  s = frame.shape  # Scale the image 4% without moving the center  T = cv2.getRotationMatrix2D((s[1]/2, s[0]/2), 0, 1.04)  frame = cv2.warpAffine(frame, T, (s[1], s[0]))  return frame


C++

void fixBorder(Mat &frame_stabilized){Mat T = getRotationvoid fixBorder(Mat &frame_stabilized){  Mat T = getRotationMatrix2D(Point2f(frame_stabilized.cols/2, frame_stabilized.rows/2), 0, 1.04);   warpAffine(frame_stabilized, frame_stabilized, T, frame_stabilized.size()); }Matrix2D(Point2f(frame_stabilized.cols/2, frame_stabilized.rows/2), 0, 1.04);warpAffine(frame_stabilized, frame_stabilized, T, frame_stabilized.size());}

结果:

我们分享的视频防抖代码的结果如上所示。我们的目标是显著减少运动,但不是完全消除它。

我们留给读者去思考如何修改代码来完全消除帧之间的移动。如果你试图消除所有的相机运动,会有什么副作用?

目前的方法只适用于固定长度的视频,而不适用于实时feed。我们不得不对这个方法进行大量修改,以获得实时视频输出,这超出了本文的范围,但这是可以实现的,更多的信息可以在这里找到。

https://abhitronix.github.io/2018/11/30/humanoid-AEAM-3/

优点和缺点

优点

这种方法对低频运动(较慢的振动)具有良好的稳定性。这种方法内存消耗低,因此非常适合嵌入式设备(如树莓派)。这种方法对视频缩放抖动有很好的效果。

缺点

这种方法对高频扰动的抵抗效果很差。如果有一个严重的运动模糊,特征跟踪将失败,结果将不是最佳的。这种方法也不适用于滚动快门失真。

References:

  1. Example video and Code reference from Nghia Ho’s post

    http://nghiaho.com/uploads/code/videostab.cpp

  2. Various References, data, and image from my website

    https://abhitronix.github.io/

  3. https://www.learnopencv.com/video-stabilization-using-point-feature-matching-in-opencv/

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

如若内容造成侵权/违法违规/事实不符,请联系七分地网进行投诉反馈,一经查实,立即删除!

相关文章

被嫌弃的贝叶斯派的逆袭

多数人第一次听说贝叶斯定理应该是在中学课堂上。那个公式看起来并不复杂&#xff0c;在一众花里胡哨的考点中显得平平无奇。但是很快&#xff0c;我们就知道了什么叫深藏不露。从高校教材到研究实战&#xff0c;贝叶斯这三个字频繁地出现在信息科学的重要议题中&#xff0c;它…

ICLR 2021论文接收统计出炉!Top20 机构,国内仅清华在榜!

转载自&#xff1a;AI科技评论ICLR 2021于前些天正式放榜&#xff0c;本次ICLR 2021一共有2997篇有效论文投稿&#xff0c;最后一共860篇被接收&#xff0c;录取率达到了28.7%&#xff0c;相比去年的26.5%有提升&#xff0c;与其他一些AI顶会大幅降低接收率相比&#xff0c;ICL…

为什么 Linux 和 macOS 不需要碎片整理

为什么这么设计&#xff08;Why’s THE Design&#xff09;是一系列关于计算机领域中程序设计决策的文章&#xff0c;我们在这个系列的每一篇文章中都会提出一个具体的问题并从不同的角度讨论这种设计的优缺点、对具体实现造成的影响。如果你有想要了解的问题&#xff0c;可以在…

GPT「高仿」问世:GPT-Neo,最大可达GPT-3大小,已开源 | AI日报

GPT“高仿”问世&#xff1a;GPT-Neo&#xff0c;最大可达GPT-3大小&#xff0c;已开源近日&#xff0c;有个名叫 EleutherAI的团队&#xff08;创始成员为&#xff1a;Connor Leahy&#xff0c;Leo Gao和Sid Black&#xff09;&#xff0c;宣布推出GPT-Neo开源项目&#xff0c…

Neighbor2Neighbor: Self-Supervised Denoising from Single Noisy Images

下面内容来自智源研究院CVPR2021预讲华为诺亚专场 1、深度学习的图像去噪方法面临的挑战 当前方法主要包括三类&#xff1a; 基于监督学习的方法&#xff1a;使用 noisy-clean 图像对进行训练&#xff08;DnCNN, FFDNet, CBDNet, SGNet&#xff09;。这类方法的难点在于&…

《Pro/ENGINEER野火版5.0从入门到精通》——1.3 体验Pro/E野火版5.0

本节书摘来自异步社区《Pro/ENGINEER野火版5.0从入门到精通》一书中的第1章&#xff0c;第1.3节&#xff0c;作者 暴风创新科技&#xff0c;更多章节内容可以访问云栖社区“异步社区”公众号查看。 1.3 体验Pro/E野火版5.0 Pro/E野火版5.0与其他软件类似&#xff0c;操作程序时…

CVPR 2021评审出炉,评审员奇葩意见遭热议 | AI日报

CVPR 2021评审出炉&#xff0c;评审员奇葩意见遭热议1月18日&#xff0c;CVPR 2021的评审结果出炉。根据CVPR 2021 程序主席、FAIR研究科学家Georgia Gkioxari近日在推特上的发文数据&#xff1a;今年共有7015篇有效提交论文&#xff0c;每篇论文都至少有3个评审结果&#xff0…

书评 | 9 年码龄工程师读 Android 经典

作为一个码龄 9 年的 Android 开发工程师&#xff0c;因业界大前端趋势&#xff0c;从18 年开始更多的时间专注在 React Native 上&#xff0c;Android 相关新技术日渐生疏了。Kotlin 和 Jetpack 等新技术一直缺乏上手了解的机会&#xff0c;是时候通过一本书体系化地了解一下相…

stylegan2 示例命令fused_bias_act.cu环境配置异常(无法打开包括文件: “tensorflow/core/framework/op.h”

在python运行stylegan2示例时,运行过程中,触发fused_bias_act.cu中的异常,可以看到fused_bias_act.cu中实际上是用c/c写的实现代码. 仔细看异常信息会发现这句话 无法打开包括文件: “tensorflow/core/framework/op.h”: 解决策略 1.首先确保你安装了c/c工具集,版本号可以有些…

中科院计算所沈华伟:GNN发展简史,诟病才是成长动力

文&#xff1a;周寅张皓图神经网络&#xff08;Graph Neural Network&#xff09;的应用在近年来蓬勃发展&#xff0c;但同时对其质疑也从未消失。诸如对与大规模图数据的存储问题&#xff0c;表达能力问题&#xff0c;以及数据集的规范问题引发了许多讨论。中科院计算所沈华伟…

赠书活动 | 数据挖掘经典入门

赠书活动在 AINLP 公众号。这本书相当受欢迎&#xff08;前两个版本累计销量超过 5 万册&#xff09;&#xff0c;尤其是受学校青睐——在此也说声抱歉&#xff0c;出于出版时间的原因&#xff0c;很多学校依然采用了旧版作为教材&#xff1b;同时也请知悉&#xff0c;新版已上…

《C语言编程初学者指南》一2.9 理解运算符优先级

本节书摘来自异步社区《C语言编程初学者指南》一书中的第2章&#xff0c;第2.9节&#xff0c;作者【美】Keith Davenport&#xff08;达文波特&#xff09; , M1ichael Vine&#xff08;维恩&#xff09;&#xff0c;更多章节内容可以访问云栖社区“异步社区”公众号查看 2.9 …

产品开发的 11 宗罪

题图 | created by freepik最近图灵君在翻看一本比较小众的书&#xff1a;《硬件产品设计与开发&#xff1a;从原型到交付》&#xff0c;没成想翻开前言和第 1 章都很惊艳&#xff0c;尤其是第 1 章总结的《产品开发的 11 宗罪》&#xff0c;真的让我受益匪浅。因为这篇文章总结…

盘点:2020 年机器学习 10 大进展

转载自&#xff1a;机器之心2020 年因为新冠疫情&#xff0c;很多人不得不在家工作和学习&#xff0c;大量人工智能学术会议也转为线上。不过在去年我们仍然看到了很多 AI 技术领域的进展。DeepMind 研究科学家 Sebastian Ruder 近日帮我们对去年的机器学习社区进行了一番总结。…

《精通自动化测试框架设计》—第1章 1.3节五天太久,还能压缩吗

本节书摘来自异步社区《精通自动化测试框架设计》一书中的第1章&#xff0c;第1.3节五天太久&#xff0c;还能压缩吗&#xff0c;作者陈冬严 , 邵杰明 , 王东刚 , 蒋涛&#xff0c;更多章节内容可以访问云栖社区“异步社区”公众号查看。 1.3 五天太久&#xff0c;还能压缩吗两…

终于!有本书把我从“看完就忘、死记硬背”的学习困境中拯救出来了!

设想一下&#xff0c;你面前有一堵由5000个魔方组成的魔方墙&#xff0c;从中间分割成两块&#xff0c;左右各2500个&#xff0c;并且它们的图案完全一致&#xff01;这时&#xff0c;有人从右边的墙上随机挑选一个魔方&#xff0c;让九个方格中的一个变换颜色&#xff0c;你能…

一秒看遍10万神经元的「绚丽烟花」,AI究竟向大脑学什么?|北大陈良怡专访...

作者&#xff1a;梦佳大脑是人类进化的高级产物&#xff0c;重量约1.5公斤&#xff0c;占体重2&#xff05;&#xff0c;功耗约20瓦&#xff0c;占全身功耗20&#xff05;&#xff0c;当前人类对大脑的认识还不足5&#xff05;&#xff0c;尚无完整的脑谱图可供参考。毫无疑问&…

一本真正讲“大数据”处理思路的书

这是我读到的第一本真正讲“大数据”处理思路的书&#xff0c;我想分享一下我读了这本书的感悟。一般情况下&#xff0c;在面对海量数据的时候&#xff0c;我们的软件架构也会跟着发生变化。当你的数据量在内存里放不下的时候&#xff0c;你就得考虑硬盘&#xff1b;当你的硬盘…

这些代码改变了科学界:从Fortran、arXiv到AlexNet

转自&#xff1a;机器之心2019 年&#xff0c;「事件视界望远镜」团队拍下了第一张黑洞照片。这张照片并非传统意义上的照片&#xff0c;而是计算得来的——将美国、墨西哥、智利、西班牙和南极多台射电望远镜捕捉到的数据进行数学转换。该团队公开了所用代码&#xff0c;使科学…

不存在完美的入门书,但是有些书在某些方面很惊艳

题图 | Technology vector created by stories - www.freepik.com前段时间收到了明发哥翻译的《Android 编程权威指南&#xff08;第4版&#xff09;》&#xff0c;许久没有打开纸质书&#xff0c;但翻阅时的纸墨味儿依旧&#xff0c;仿佛回到了几年前初学 XML 布局的时候。我从…