OpenCV(opencv_apps)在ROS中的视频图像的应用(重点讲解哈里斯角点的检测)
1、引言
通过opencv_apps,你可以在ROS中以最简单的方式运行OpenCV提供的许多功能,也就是说,运行一个与功能相对应的launch启动文件,就可以跳过为OpenCV的许多功能编写OpenCV应用程序代码,非常的方便。
对于想熟悉每个细节的伙伴们,可以去看源码,对于熟悉视觉操作很有帮助。
官方说明:http://wiki.ros.org/opencv_apps
github源码:https://github.com/ros-perception/opencv_apps
2、启动操作
2.1、opencv_apps.launch
先来启动摄像头等相关操作,需要启动opencv_apps.launch文件,我们先来了解下:
gedit /home/jetson/workspace/catkin_ws/src/jetbot_ros/launch/opencv_apps.launch
<launch><arg name="img_flip" default="False"/><arg name="img_transform" default="True"/><group if="$(arg img_transform)"><arg name="img_topic" default="/csi_cam_0/image_raw"/><include file="$(find jetson_nano_csi_cam)/launch/jetson_csi_cam.launch"/><node name="img_transform" pkg="jetbot_ros" type="img_transform.py" output="screen"><param name="img_flip" type="bool" value="$(arg img_flip)"/><param name="img_topic" type="string" value="$(arg img_topic)"/></node></group>
</launch>
这里<include>节点包含一个jetson_csi_cam.launch启动文件以及一个名为img_transform的节点
其中jetson_csi_cam.launch我们查看下里面的内容:
cat /home/jetson/workspace/catkin_ws/src/jetson_nano_csi_cam_ros/launch/jetson_csi_cam.launch
里面是一些摄像头的参数设置和启动摄像头,通过GSCAM开源包将GStreamer图像流引入到ROS中,转换成sensor_msgs/Image类型的Image话题,发布到ROS中,供其他节点使用。
2.2、img_transform.py
然后就是做这些操作的节点,我们来看下它的源码:
gedit /home/jetson/workspace/catkin_ws/src/jetbot_ros/scripts/img_transform.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
import cv2 as cv
from cv_bridge import CvBridge
from sensor_msgs.msg import Imagedef topic(msg):if not isinstance(msg, Image):returnbridge = CvBridge()frame = bridge.imgmsg_to_cv2(msg, "bgr8")# Canonical input image sizeframe = cv.resize(frame, (640, 480))if img_flip == True: frame = cv.flip(frame, 1)# opencv mat -> ros msgmsg = bridge.cv2_to_imgmsg(frame, "bgr8")pub_img.publish(msg)if __name__ == '__main__':rospy.init_node("pub_img", anonymous=False)img_topic = rospy.get_param("~img_topic", "/csi_cam_0/image_raw")img_flip = rospy.get_param("~img_flip", False)sub_img = rospy.Subscriber(img_topic, Image, topic)pub_img = rospy.Publisher("/image", Image, queue_size=10)rate = rospy.Rate(2)rospy.spin()
这里就是定义一个pub_img节点,订阅CSI摄像头相关的话题,然后通过Image话题进行发布,供其余节点使用。其中获取参数:rospy.get_param("~img_topic", "/csi_cam_0/image_raw"),如果没有在~img_topic获取到,就使用/csi_cam_0/image_raw默认值。同样的rospy.get_param("~img_flip", False)如果没有获取到~img_flip的值,就默认为False
2.3、打开相机
熟悉摄像头的相关操作之后,我们就来做一些准备工作,开启相机:
roslaunch jetbot_ros opencv_apps.launch
查看方式:rqt_image_view,如下图:
或者网页查看:rosrun web_video_server web_video_server
然后使用IP+端口就可以查看了,如下图:
然后点击里面的话题,就可以看到摄像视频了,如下图:
我们来看下开启了哪些话题:rostopic list
/csi_cam_0/camera_info
/csi_cam_0/image_raw
/csi_cam_0/image_raw/compressed
/csi_cam_0/image_raw/compressed/parameter_descriptions
/csi_cam_0/image_raw/compressed/parameter_updates
/csi_cam_0/image_raw/compressedDepth
/csi_cam_0/image_raw/compressedDepth/parameter_descriptions
/csi_cam_0/image_raw/compressedDepth/parameter_updates
/csi_cam_0/image_raw/theora
/csi_cam_0/image_raw/theora/parameter_descriptions
/csi_cam_0/image_raw/theora/parameter_updates
/image
/rosout
/rosout_agg
是一些关于csi摄像头相关的话题,接下来我们对里面大量的示例做一个演示
3、哈里斯角点
因为我们都是在opencv_apps包里面,所以先来这个所在工作区间的这个包的launch目录里面。
查看下有哪些启动文件:ls /home/jetson/workspace/catkin_ws/src/opencv_apps/launch/
adding_images.launch hough_circles.launch
camshift.launch hough_lines.launch
contour_moments.launch hsv_color_filter.launch
convex_hull.launch lk_flow.launch
corner_harris.launch people_detect.launch
discrete_fourier_transform.launch phase_corr.launch
edge_detection.launch pyramids.launch
face_detection.launch rgb_color_filter.launch
face_recognition.launch segment_objects.launch
fback_flow.launch simple_flow.launch
find_contours.launch smoothing.launch
general_contours.launch threshold.launch
goodfeature_track.launch watershed_segmentation.launch
hls_color_filter.launch
可以看到对图像操作的功能还是挺多的,有霍夫圆、霍夫直线、轮廓矩、LK光流、哈里斯角点、边缘、人物、面部识别等等
3.1、corner_harris.launch
判断某个点是图像中的角点,这里的对角点的检测,我们花多点时间重点来说明下,后面的节点基本就是展示为主。
roslaunch opencv_apps corner_harris.launch
启动如下,使用一张棋盘格式的图片让它识别:
可以看到图片中的角点,有很多的小圆圈给标注着,这里的角点检测的多少和准确度,取决于上面的threshold阈值大小,可以自行调节,调小了,角点数量就会多,相对而言准确度也在下降,调大阈值,角点数量就相应减少,准确度要高。
我们来看下这个启动文件里面的内容:
cat /home/jetson/workspace/catkin_ws/src/opencv_apps/launch/corner_harris.launch
<launch><arg name="node_name" default="corner_harris" /><arg name="image" default="image" doc="The image topic. Should be remapped to the name of the real image topic." /><arg name="use_camera_info" default="false" doc="Indicates that the camera_info topic should be subscribed to to get the default input_frame_id. Otherwise the frame from the image message will be used." /><arg name="debug_view" default="true" doc="Specify whether the node displays a window to show image" /><arg name="queue_size" default="3" doc="Specigy queue_size of input image subscribers" /><arg name="threshold" default="200" doc="Threshold value of a circle around corners's norm" /><!-- corner_harris.cpp --><node name="$(arg node_name)" pkg="opencv_apps" type="corner_harris" ><remap from="image" to="$(arg image)" /><param name="use_camera_info" value="$(arg use_camera_info)" /><param name="debug_view" value="$(arg debug_view)" /><param name="queue_size" value="$(arg queue_size)" /></node>
</launch>
3.2、corner_harris.cpp
前面是一些参数设置,后面是一个node节点部分,其中type="corner_harris"可以知道使用的是C++写的,因为如果是Python写的,就是type="corner_harris.py"这样的形式,当然那里也注释说明了是corner_harris.cpp
其中C++代码文件的地址:ls /home/jetson/workspace/catkin_ws/build/opencv_apps
我们来看下这个哈里斯角点的实际代码:
gedit /home/jetson/workspace/catkin_ws/build/opencv_apps/corner_harris.cpp
/*********************************************************************
* Software License Agreement (BSD License)
*
* Copyright (c) 2016, Kentaro Wada.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of the Kentaro Wada nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*********************************************************************/#include <ros/ros.h>
#include <nodelet/loader.h>int main(int argc, char **argv)
{ros::init(argc, argv, "corner_harris", ros::init_options::AnonymousName);if (ros::names::remap("image") == "image") {ROS_WARN("Topic 'image' has not been remapped! Typical command-line usage:\n""\t$ rosrun image_rotate image_rotate image:=<image topic> [transport]");}// need to use 1 worker thread to prevent freezing in imshow, calling imshow from mutiple threads//nodelet::Loader manager(false);ros::param::set("~num_worker_threads", 1); // need to call Loader(bool provide_ros_api = true);nodelet::Loader manager(true);nodelet::M_string remappings;nodelet::V_string my_argv(argv + 1, argv + argc);my_argv.push_back("--shutdown-on-close"); // Internalmanager.load(ros::this_node::getName(), "opencv_apps/corner_harris", remappings, my_argv);ros::spin();return 0;
}
这段代码就是初始化corner_harris节点,image话题的重映射等,然后用圆圈来标注角点,这个操作会用到接下来要讲的一个插件。
3.3、corner_harris_nodelet.cpp
上面的核心代码,会用到Nodelet,关于这个Nodelet插件的解释:
允许用户在ROS节点中添加自定义功能,Nodelet使得开发人员能够将复杂的代码封装到可重用的插件中,这些插件可以像其他ROS节点一样进行部署和通信,开发人员可以编写更加模块化和可维护的代码,提高ROS系统的可扩展性和可重用性。
更关键的是效率问题,Nodelet提供一种方法,可以让多个算法程序在一个进程中,使用共享指针shared_ptr来实现零拷贝通信,以降低因为拷贝传输大数据(比如图像流,点云等)而延迟的问题,换句话说就是将多个node捆绑在一起管理,使得同一个manager里面的话题的数据传输更快,因为不会在进程内传递消息时进行复制而产生的效率下降。
查看插件文件:ls /home/jetson/workspace/catkin_ws/src/opencv_apps/src/nodelet
我们打开哈里斯角点的插件代码来看下:
gedit /home/jetson/workspace/catkin_ws/src/opencv_apps/src/nodelet/corner_harris_nodelet.cpp
// -*- coding:utf-8-unix; mode: c++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
/*********************************************************************
* Software License Agreement (BSD License)
*
* Copyright (c) 2016, JSK Lab.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of the Kei Okada nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*********************************************************************/
#include <ros/ros.h>
#include "opencv_apps/nodelet.h"
#include <image_transport/image_transport.h>
#include <sensor_msgs/image_encodings.h>
#include <cv_bridge/cv_bridge.h>#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>#include <dynamic_reconfigure/server.h>
#include "opencv_apps/CornerHarrisConfig.h"// https://github.com/opencv/opencv/blob/master/samples/cpp/tutorial_code/TrackingMotion/cornerHarris_Demo.cpp
/*** @function cornerHarris_Demo.cpp* @brief Demo code for detecting corners using Harris-Stephens method* @author OpenCV team*/namespace opencv_apps
{
class CornerHarrisNodelet : public opencv_apps::Nodelet
{image_transport::Publisher img_pub_;image_transport::Subscriber img_sub_;image_transport::CameraSubscriber cam_sub_;ros::Publisher msg_pub_;boost::shared_ptr<image_transport::ImageTransport> it_;typedef opencv_apps::CornerHarrisConfig Config;typedef dynamic_reconfigure::Server<Config> ReconfigureServer;Config config_;boost::shared_ptr<ReconfigureServer> reconfigure_server_;int queue_size_;bool debug_view_;std::string window_name_;static bool need_config_update_;int threshold_;void reconfigureCallback(Config& new_config, uint32_t level){config_ = new_config;threshold_ = config_.threshold;}const std::string& frameWithDefault(const std::string& frame, const std::string& image_frame){if (frame.empty())return image_frame;return frame;}void imageCallbackWithInfo(const sensor_msgs::ImageConstPtr& msg, const sensor_msgs::CameraInfoConstPtr& cam_info){doWork(msg, cam_info->header.frame_id);}void imageCallback(const sensor_msgs::ImageConstPtr& msg){doWork(msg, msg->header.frame_id);}static void trackbarCallback(int /*unused*/, void* /*unused*/){need_config_update_ = true;}void doWork(const sensor_msgs::ImageConstPtr& image_msg, const std::string& input_frame_from_msg){// Work on the image.try{// Convert the image into something opencv can handle.cv::Mat frame = cv_bridge::toCvShare(image_msg, sensor_msgs::image_encodings::BGR8)->image;// Do the workcv::Mat dst, dst_norm, dst_norm_scaled;dst = cv::Mat::zeros(frame.size(), CV_32FC1);cv::Mat src_gray;if (frame.channels() > 1){cv::cvtColor(frame, src_gray, cv::COLOR_BGR2GRAY);}else{src_gray = frame;cv::cvtColor(src_gray, frame, cv::COLOR_GRAY2BGR);}/// Detector parametersint block_size = 2;int aperture_size = 3;double k = 0.04;/// Detecting cornerscv::cornerHarris(src_gray, dst, block_size, aperture_size, k, cv::BORDER_DEFAULT);/// Normalizingcv::normalize(dst, dst_norm, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());cv::convertScaleAbs(dst_norm, dst_norm_scaled);/// Drawing a circle around cornersfor (int j = 0; j < dst_norm.rows; j++){for (int i = 0; i < dst_norm.cols; i++){if ((int)dst_norm.at<float>(j, i) > threshold_){cv::circle(frame, cv::Point(i, j), 5, cv::Scalar(0), 2, 8, 0);}}}/// Create windowif (debug_view_){cv::namedWindow(window_name_, cv::WINDOW_AUTOSIZE);const int max_threshold = 255;if (need_config_update_){config_.threshold = threshold_;reconfigure_server_->updateConfig(config_);need_config_update_ = false;}cv::createTrackbar("Threshold:", window_name_, &threshold_, max_threshold, trackbarCallback);}if (debug_view_){cv::imshow(window_name_, frame);int c = cv::waitKey(1);}// Publish the image.sensor_msgs::Image::Ptr out_img =cv_bridge::CvImage(image_msg->header, sensor_msgs::image_encodings::BGR8, frame).toImageMsg();img_pub_.publish(out_img);}catch (cv::Exception& e){NODELET_ERROR("Image processing error: %s %s %s %i", e.err.c_str(), e.func.c_str(), e.file.c_str(), e.line);}}void subscribe() // NOLINT(modernize-use-override){NODELET_DEBUG("Subscribing to image topic.");if (config_.use_camera_info)cam_sub_ = it_->subscribeCamera("image", queue_size_, &CornerHarrisNodelet::imageCallbackWithInfo, this);elseimg_sub_ = it_->subscribe("image", queue_size_, &CornerHarrisNodelet::imageCallback, this);}void unsubscribe() // NOLINT(modernize-use-override){NODELET_DEBUG("Unsubscribing from image topic.");img_sub_.shutdown();cam_sub_.shutdown();}public:virtual void onInit() // NOLINT(modernize-use-override){Nodelet::onInit();it_ = boost::shared_ptr<image_transport::ImageTransport>(new image_transport::ImageTransport(*nh_));pnh_->param("queue_size", queue_size_, 3);pnh_->param("debug_view", debug_view_, false);if (debug_view_){always_subscribe_ = true;}window_name_ = "CornerHarris Demo";reconfigure_server_ = boost::make_shared<dynamic_reconfigure::Server<Config> >(*pnh_);dynamic_reconfigure::Server<Config>::CallbackType f =boost::bind(&CornerHarrisNodelet::reconfigureCallback, this, _1, _2);reconfigure_server_->setCallback(f);img_pub_ = advertiseImage(*pnh_, "image", 1);onInitPostProcess();}
};
bool CornerHarrisNodelet::need_config_update_ = false;
} // namespace opencv_appsnamespace corner_harris
{
class CornerHarrisNodelet : public opencv_apps::CornerHarrisNodelet
{
public:virtual void onInit() // NOLINT(modernize-use-override){ROS_WARN("DeprecationWarning: Nodelet corner_harris/corner_harris is deprecated, ""and renamed to opencv_apps/corner_harris.");opencv_apps::CornerHarrisNodelet::onInit();}
};
} // namespace corner_harris#include <pluginlib/class_list_macros.h>
PLUGINLIB_EXPORT_CLASS(opencv_apps::CornerHarrisNodelet, nodelet::Nodelet);
PLUGINLIB_EXPORT_CLASS(corner_harris::CornerHarrisNodelet, nodelet::Nodelet);
主要关注其中检测角点的方法:
cv::cornerHarris(src_gray, dst, block_size, aperture_size, k, cv::BORDER_DEFAULT);
参数说明如下:
src_gray:输入的灰度Mat矩阵或浮点图像
dst:存储着哈里斯角点检测的结果,跟源图的尺寸和类型一样
block_size:邻域的大小
aperture_size:Sobel边缘检测滤波器大小
k:Harris中间参数,经验值0.04~0.06
cv::BORDER_DEFAULT:插值类型
我们也可以看到在发布和订阅时,用到的就是指针。
发布时:
sensor_msgs::Image::Ptr out_img =cv_bridge::CvImage(image_msg->header, sensor_msgs::image_encodings::BGR8, frame).toImageMsg();
img_pub_.publish(out_img);
订阅时:
Nodelet::onInit();
it_ = boost::shared_ptr<image_transport::ImageTransport>(new image_transport::ImageTransport(*nh_));if (config_.use_camera_info)cam_sub_ = it_->subscribeCamera("image", queue_size_, &CornerHarrisNodelet::imageCallbackWithInfo, this);elseimg_sub_ = it_->subscribe("image", queue_size_, &CornerHarrisNodelet::imageCallback, this);
这样我们在消息传递时,就只需要传指针了,当然这里是针对同一台设备的进程间通信,如果是不同设备那还是需要解引用传输实际内容,因为我们知道ROS的分布节点进行通信的协议是XML-RPC,本质也是HTTP协议,只不过编码格式是XML类型,它们之间的传输还得是拷贝内容进行通信。
查看节点关系:rqt_graph,我这里将调试节点隐藏,显得更清晰点,如下图:
可以看到CSI摄像头图像获取需要经过转换之后最终通过/Image话题发布给哈里斯角点算法处理。
识别角点的原理,简单来说就是在特征窗口里面,如果灰度发生了较大的变化,就认为这里是一个角点,有兴趣的可以查阅:harris.cpp
4、霍夫直线检测
接下来的部分,就没有上述那么去分析了,只是熟悉下常用的几个功能。
霍夫直线的检测在计算机视觉和图像处理中用途广泛,可以用于边缘检测、直线检测等。
实际场景中,可以通过从图像中检测出边缘,然后通过识别直线或曲线,将这些边缘连接起来,形成完整的物体。
另外无人驾驶的发展,对于自动化检测道路、车道线等应用也有着广泛的应用。
启动launch文件:roslaunch opencv_apps hough_lines.launch
很好的检测到了我身上的衣服以及上面的“中国”文字,如下图:
5、图像轮廓矩
contour_moments.launch是启动识别图像中轮廓的矩函数,这里的轮廓矩也可以理解成轮廓的特征,它也有着很广泛的应用:
目标识别:提取图像中物体的轮廓特征,可以对目标进行识别和分类。
目标检测:通过检测物体的形状和轮廓,来确定目标的位置。
图像分割:因为可以对不同的区域进行目标的识别,所以也可以帮助其进行图像的分割。
医学领域:可以用来识别图像中的组织器官和患病部位,从而提取特征,进行医学的诊断。
启动:roslaunch opencv_apps contour_moments.launch,如下图:
6、LK光流
LK光流是描述目标运动的方法,利用LK光流可以实现对目标的追踪,从而知道目标的位姿。
LK光流法的前提条件如下:
亮度恒定:一个像素点随着时间的变化,其亮度值(像素灰度值)是不能变化的。
小运动:时间的变化不会引起位置的剧烈变化。这样才能利用相邻帧之间的位置变化引起的灰度值变化,去求取灰度对位置的偏导数。
空间一致:前一帧的相邻像素点在后一帧也是相邻的,因为为了求解x,y方向的速度,需要建立方程组,而空间一致假设就可以利用邻域n个像素点来建立n个方程。
启动:roslaunch opencv_apps lk_flow.launch,如下图:
7、相机相位位移
检测相机移动的快慢,或者里面目标的运动快慢
启动:roslaunch opencv_apps phase_corr.launch,如下图:
移动越快,圆就越大
大概的介绍就先到这儿吧,另外一些关于OpenCV的文章,有兴趣的可以查阅:
OpenCV自带的HAAR级联分类器对脸部(人脸、猫脸等)的检测识别
OpenCV的HSV颜色空间在无人车中颜色识别的应用
相关文章:

OpenCV(opencv_apps)在ROS中的视频图像的应用(重点讲解哈里斯角点的检测)
1、引言 通过opencv_apps,你可以在ROS中以最简单的方式运行OpenCV提供的许多功能,也就是说,运行一个与功能相对应的launch启动文件,就可以跳过为OpenCV的许多功能编写OpenCV应用程序代码,非常的方便。 对于想熟悉每个…...

常见排序算法之插入排序类
插入排序,是一种简单直观的排序算法,工作原理是将一个记录插入到已经排好序的有序表中,从而形成一个新的、记录数增1的有序表。在实现过程中,它使用双层循环,外层循环对除了第一个元素之外的所有元素,内层循…...
Dubbo服务消费端远程调用过程剖析
1 Dubbo服务消费端远程调用过程概述 (1)当消费方调用远程服务的方法时,会被InvokerInvocationHandler拦截,执行其invoke()方法,创建RpcInvocation对象; (2)接着会选择远程调用的负…...

华硕荣获“EPEAT Climate+ Champion”永续先驱称号
华硕持续深耕永续理念,努力提供低碳排放、高效能产品,并被全球电子委员会授予“EPEAT Climate Champion”称号。这一荣誉再次表明了华硕在永续管理方面的承诺,并凸显了华硕在追求永续发展上的决心。 华硕通过设立“科学基础减碳目标”、“再生…...

基于QT使用OpenGL,加载obj模型,进行鼠标交互
目录 功能分析(需求分析)技术点分析OpenGL立即渲染模式可编程渲染管线模式 QOpenGLWidget派生类 glwidget逻辑glwidget.hglwidget.cpp 鼠标交互功能obj格式介绍 效果bunnyCayman_GT 功能分析(需求分析) 基于QT平台,使…...

三大赛题指南发布!2023 冬季波卡黑客松本周末开启 Workshop
2023 年一众黑客松赛事中,为什么我们建议您选择波卡黑客松大赛?或许答案在于——作为开发者极度友好的技术生态,波卡能够从参赛者的立场出发,为大家提供从 0 到 1 实现项目孵化成长的机会。这里聚集了一线技术专家的资源力量&…...
数据结构与算法(Java版) | 算法的空间复杂度简介
关于算法的空间复杂度,下面我给大家作一个简单介绍。 类似于时间复杂度的讨论,一个算法的空间复杂度(Space Complexity)定义为该算法所耗费的存储空间,同样,它也是问题规模n的一个函数。 其实,…...
大数据-之LibrA数据库系统告警处理(ALM-12037 NTP服务器异常)
告警解释 当NTP服务器异常时产生该告警。 当NTP服务器异常消除时,该告警恢复。 告警属性 告警ID 告警级别 可自动清除 12037 严重 是 告警参数 参数名称 参数含义 ServiceName 产生告警的服务名称。 RoleName 产生告警的角色名称。 HostName 异常N…...

烟草5G智慧工厂数字孪生可视化平台,赋能烟草工业数字化智慧转型
随着卷烟工厂提质增效需求增强,信息化建设推进及生产制造系统智能化改革发展,各生产单元逐步升级完善数字化,最终实现智能制造成为必然趋势。因此,5G卷烟加工工厂的数字化转型迫在眉睫。中国烟草制造行业正迈向全新的市场经济时代…...

PHP编写采集药品官方数据的程序
在 PHP 中编写爬虫程序,首先我们需要引入一些必要的库,如 curl 和 file_get_contents。然后,我们需要设置爬虫ip信息,以便我们可以从指定的爬虫ip服务器上获取数据。 // 引入必要的库 require_once curl.php;// 设置爬虫ip信息 $p…...

解决Jenkins执行git脚本时报错:No such device or address问题
问题现象: Jenkins执行BeanShell脚本时,报错:jenkins fatal: could not read Username for http://112.11.120.1: No such device or address 解决方案: 解决服务器拉取git仓库的代码权限,使用高级子模块克隆功能。…...

LCD英文字模库(16x8)模拟测试程序
字模 字模,就是把文字符号转换为LCD能识别的像素点阵信息。 电子发烧友可能都熟悉字模的用途。就是调用者通过向LCD模块发送字模数据,LCD根据字模数据在LCD面板上相应的像素描绘出图形或文字。 现在,大部分的LCD都内置了字模库,…...
二分法
文章目录 二分法概述二分 > value最左的位置二分 < value最右的位置局部最小值问题 二分法概述 什么是二分法呢?相信大家都有所了解,举个最经典的二分的例子。 给定一个整型有序数组,和一个值 v a l u e value value,如…...

Linux文件类型与权限及其修改
后面我们写代码时,写完可能会出现没有执行权限什么的,所以我们要知道文件都有哪些权限和类型。 首先 就像我们之前目录结构图里面有个/dev,它就是存放设备文件的,也就是说,哪怕是一个硬件设备,例如打印机啥的…...

RPC 框架 openfeign 介绍和学习使用总结
一、基本概念 RPC 远程过程调用(Remote Procedure Call)的缩写形式 Birrell 和 Nelson 在 1984 发表于 ACM Transactions on Computer Systems 的论文《Implementing remote procedure calls》对 RPC 做了经典的诠释。 RPC 是指计算机 A 上的进程&am…...
大厂真题:【DP/贪心】字节跳动2023秋招-小红的 01 串
题目描述与示例 题目描述 小红拿到了一个 01 串,她准备将若干个字符1 染成红色,将若干个字符0 染成蓝色,但有个限制:如果一个0 和一个1 相邻,那么它们不能同时染色。 小红想知道,最多可以染多少个字符&a…...

【技术类-01】doc转PDF程序卡死的解决方案,
摘要: 1、报错: raise AttributeError("%s.%s" % (self._username_, attr))) 2、表现:doc转PDF卡死(白条不动或出现以上英文) 3、解决:在docx保存代码行后面加上time.sleep(3) 4、…...

探索未来,开启无限可能:打造智慧应用,亚马逊云科技大语言模型助您一臂之力
文章目录 什么是大模型?大模型训练方法亚马逊云科技推出生成式AI新工具 —— aws toolkit使用教程 总结 什么是大模型? 近期,生成式大模型是人工智能领域的研究热点。这些生成式大模型,诸如文心一言、文心一格、ChatGPT、Stable …...

HTML点击链接强制触发下载
常见网页中会有很多点击链接即下载的内容,以下示范一下如何实现 <a href"文件地址" download"下载的文件名字(不包括后缀)">强制下载</a> 下面举个例子: <a href"./image/test.jpg"…...

Paimon 与 Spark 的集成(一)
Paimon Apache Paimon (incubating) 是一项流式数据湖存储技术,可以为用户提供高吞吐、低延迟的数据摄入、流式订阅以及实时查询能力。Paimon 采用开放的数据格式和技术理念,可以与 ApacheFlink / Spark / Trino 等诸多业界主流计算引擎进行对接…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...

汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...

HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...

android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用
前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...
加密通信 + 行为分析:运营商行业安全防御体系重构
在数字经济蓬勃发展的时代,运营商作为信息通信网络的核心枢纽,承载着海量用户数据与关键业务传输,其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级,传统安全防护体系逐渐暴露出局限性&a…...
写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里
写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里 脚本1 #!/bin/bash #定义变量 ip10.1.1 #循环去ping主机的IP for ((i1;i<10;i)) doping -c1 $ip.$i &>/dev/null[ $? -eq 0 ] &&am…...

ubuntu中安装conda的后遗症
缘由: 在编译rk3588的sdk时,遇到编译buildroot失败,提示如下: 提示缺失expect,但是实测相关工具是在的,如下显示: 然后查找借助各个ai工具,重新安装相关的工具,依然无解。 解决&am…...