OpenCV2.4.10之samples_cpp_tutorial-code_learn-----ImgProc(图像处理)

2024-08-25 05:18

本文主要是介绍OpenCV2.4.10之samples_cpp_tutorial-code_learn-----ImgProc(图像处理),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本系列学习笔记参考自OpenCV2.4.10之 opencv\sources\samples\cpp\tutorial_code和 http://www.opencv.org.cn/opencvdoc/2.3.2/html/genindex.html


      本博文将继续学习 OpenCV2.4.10中tutorial-code下的ImgProc,还有对于涉及到的知识才进行解释,如果没有涉及到相关知识,不进行系列性的介绍。顾名思义该文件夹介绍的图像处理相关的Demo,该文件夹下包括以下7个例子:
1.AddingImages.cpp(图像线性叠加)
该Demo的源码及相关的中文如下所示:
#include "stdafx.h"    //预编译头文件    /*** @图像简单线性叠加 ( 叠加公式:dst = alpha*src1 + beta*src2,其中src1和src2为读取的需要叠加的图像,alpha和beta分别为src1和src2两张图像的权重,且alpha+ beta=1,dst为叠加合成后的图像)*/#include "opencv2/highgui/highgui.hpp"
#include <iostream>using namespace cv;int main( void )
{double alpha = 0.5; double beta; double input;Mat src1, src2, dst;/// 询问并输入第一张图像的权重std::cout<<" Simple Linear Blender "<<std::endl;std::cout<<"-----------------------"<<std::endl;std::cout<<"* Enter alpha [0-1]: ";	std::cin>>input;// 权重alpha必须为[0,1],否则错误if( alpha >= 0 && alpha <= 1 ){ alpha = input; }// 读取两张需要进行叠加的图像 (注意,需要叠加的图像是相同大小像素点,同时类型也相同)// imread第二个参数默认为1,读取为3通道彩色图像src1 = imread("D:\\opencv\\sources\\samples\\cpp\\tutorial_code\\images\\LinuxLogo.jpg");src2 = imread("D:\\opencv\\sources\\samples\\cpp\\tutorial_code\\images\\WindowsLogo.jpg");//对读取结果判断if( !src1.data ) { std::cout<< "Error loading src1"<<std::endl; return -1; }if( !src2.data ) { std::cout<< "Error loading src2"<<std::endl; return -1; }/// 创建窗口namedWindow("Linear Blend", 1);//计算第二张图像的权重beta = ( 1.0 - alpha );//线性叠加函数addWeighted( src1, alpha, src2, beta, 0.0, dst);//显示图像imshow( "Linear Blend", dst );waitKey(0);return 0;
}

当我们alpha分别取0,0.5,1的时候,运行结果如下图所示:




不难看出,根据叠加公式 dst = alpha*src1 + beta*src2(alpha+beta=1);当alpha=0时,beta=1,dst =src2(显示WindowsLogo.jpg),当alpha=1时,beta=0,dst =src1(显示LinuxLogo.jpg)。当alpha=0.5时,beta=0.5,dst =0.5*src1+0.5*src2(显示叠加效果图片)。(gramma=0,前提)
下面我们着重看看 addWeighted, addWeighted的函数声明为:C++: void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1)
其中src1为第一张图像数据,src为第二章图像数据,alpha和beta分别为两张图像的叠加权重,gamma为常数项。dst为合成后的图像,dtype为合成后的图像的位深,默认值为-1。(关于位深:可以理解为每个像素值所表示所需的位数,比如8位,16位等,位数越高表示的颜色越多,当然位数越高存储空间和计算量都会大增。)
   实际上addWeighted内部实现原理公式为:



2 .BasicLinearTransforms.cpp(图像基本的线性变换)
源码及详细注释如下:
#include "stdafx.h"    //预编译头文件    /*** 改变图像的亮度和对比度*/#include "opencv2/highgui/highgui.hpp"
#include <iostream>using namespace cv;double alpha; /*图像对比度*/
int beta;  /*图像亮度*/int main( int, char** argv )
{/// 读取图像Mat image = imread("D:\\opencv\\lena.png");Mat new_image = Mat::zeros( image.size(), image.type() );/// 初始化对比度和亮度,其中对比度在[1.0-3.0],亮度在[0-100]std::cout<<" Basic Linear Transforms "<<std::endl;std::cout<<"-------------------------"<<std::endl;std::cout<<"* Enter the alpha value [1.0-3.0]: ";std::cin>>alpha;std::cout<<"* Enter the beta value [0-100]: "; std::cin>>beta;///新的图像公式为 new_image(i,j) = alpha*image(i,j) + beta//我们可以使用简单的成员函数进行对比度和亮度的改变如:/// image.convertTo(new_image, -1, alpha, beta);/// 但是这里想为读者展示如果在像素级别进行操作 :)for( int y = 0; y < image.rows; y++ ){ for( int x = 0; x < image.cols; x++ ){ for( int c = 0; c < 3; c++ ){new_image.at<Vec3b>(y,x)[c] = saturate_cast<uchar>( alpha*( image.at<Vec3b>(y,x)[c] ) + beta );}}}/// 创建窗口namedWindow("Original Image", 1);namedWindow("New Image", 1);/// 显示图像imshow("Original Image", image);imshow("New Image", new_image);/// Wait until user press some keywaitKey();return 0;
}

运行截图如下:

这里需要对如下三重循环进行解释:

 for( int y = 0; y < image.rows; y++ ){ for( int x = 0; x < image.cols; x++ ){ for( int c = 0; c < 3; c++ ){new_image.at<Vec3b>(y,x)[c] = saturate_cast<uchar>( alpha*( image.at<Vec3b>(y,x)[c] ) + beta );}}}

图像是由无数个像素点组成的,这些像素点是由一行一行进行存储的,这样外层两个for循环就不难理解了,其作用是遍历整张图像的像素点。第三层循环的意思是对每个像素点的三个通道值进行遍历,因为我们读入的是三通道彩色图像,每个像素点的颜色值由红,滤,蓝三原色合成。所以要改变三通道图像的一个像素值就需要对该像素的三个通道的值都进行改变。
另外要解释一下 new_image.at<Vec3b>(y,x)[c],new_image为Mat类型,at为mat类型的成员函数,其函数原型如下:
template<typename _Tp> inline _Tp& Mat::at(int i0, int i1)

可以看出at成员函数为一个内联的模板函数。另外Vec3b为一个类模板特例化的后的类型定义,代表一个三个元素的向量或者数组:
typedef Vec<uchar, 3> Vec3b;
template<typename _Tp, int cn> class Vec : public Matx<_Tp, cn, 1>
所以 new_image.at<Vec3b>(y,x)返回的将是一个Vec3b类型的向量,这个向量中有三个值(代表三个通道颜色),所以要遍历这三个值需要用数组的方式进行索引new_image.at<Vec3b>(y,x)[c]。
此外
saturate_cast为一个重载的函数模板,用于像素值的溢出保护。可参考点击打开链接:



3.Morphology_1.cpp(图像的膨胀与腐蚀)
#include "stdafx.h"    //预编译头文件    /*** @图像膨胀与腐蚀Demo*/#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>using namespace cv;///全局变量
Mat src, erosion_dst, dilation_dst;int erosion_elem = 0;
int erosion_size = 0;
int dilation_elem = 0;
int dilation_size = 0;
int const max_elem = 2;
int const max_kernel_size = 21;/** 膨胀腐蚀函数声明 */
void Erosion( int, void* );
void Dilation( int, void* );/**
主函数*/
int main( int, char** argv )
{///加载图片src = imread("D:\\opencv\\lena.png");if( !src.data ){ return -1; }/// 创建窗口namedWindow( "Erosion Demo", WINDOW_AUTOSIZE );namedWindow( "Dilation Demo", WINDOW_AUTOSIZE );moveWindow( "Dilation Demo", src.cols, 0 );/// 创建腐蚀的滑动条createTrackbar( "Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Erosion Demo",&erosion_elem, max_elem,Erosion );createTrackbar( "Kernel size:\n 2n +1", "Erosion Demo",&erosion_size, max_kernel_size,Erosion );/// 创建膨胀的滑动条createTrackbar( "Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Dilation Demo",&dilation_elem, max_elem,Dilation );createTrackbar( "Kernel size:\n 2n +1", "Dilation Demo",&dilation_size, max_kernel_size,Dilation );/// 开始Erosion( 0, 0 );Dilation( 0, 0 );waitKey(0);return 0;
}/*** @腐蚀函数*/
void Erosion( int, void* )
{int erosion_type = 0;if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; }else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; }else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }Mat element = getStructuringElement( erosion_type,Size( 2*erosion_size + 1, 2*erosion_size+1 ),Point( erosion_size, erosion_size ) );/// 进行腐蚀操作erode( src, erosion_dst, element );imshow( "Erosion Demo", erosion_dst );
}/*** @膨胀函数*/
void Dilation( int, void* )
{int dilation_type = 0;if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; }else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; }else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }Mat element = getStructuringElement( dilation_type,Size( 2*dilation_size + 1, 2*dilation_size+1 ),Point( dilation_size, dilation_size ) );/// 进行膨胀操作dilate( src, dilation_dst, element );imshow( "Dilation Demo", dilation_dst );
}
运行结果如下:



首先介绍函数createTrackbar,其函数声明:C++: int createTrackbar(const string& trackbarname, const string& winname, int* value, int count, TrackbarCallback onChange=0, void*userdata=0)
trackbarname为滑动条名称,winname为滑动条所在窗口的窗口名称,value为一个整型指针,指向滑块位置,count为滑块位置最大位置,最小值默认为0. onChange位一个回调函数指针,滑块位置一旦改变将会调用该回调函数,回调函数的函数原型必须为void Foo(int,void*),其中Foo为自定义的回调函数名。userdata为用户数据传递给回调函数,使用该值可不比使用全局变量进行值传递。
接下来介绍getStructuringElement,函数原型为:C++: Mat getStructuringElement(int shape, Size ksize, Point anchor=Point(-1,-1))该函数的功能是生产一个特定形状和大小的图像元素进行图像形态学操作。shape有三个值分别为:
MORPH_RECT(矩形元素),MORPH_ELLIPSE(圆形元素)等等。ksize为矩形元素大小,anchor仅仅当shape为MORPH_CROSS时才有效。


  最后erode函数和dilate函数,两个函数声明分别为:C++: void erode(InputArray src, OutputArray dst, InputArray element, Point anchor=Point(-1,-1), int iterations=1, intborderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() )
C++:   void  dilate ( InputArray  src , OutputArray  dst , InputArray  element , Point  anchor =Point(-1,-1), int  iterations =1, int borderType =BORDER_CONSTANT, const Scalar&  borderValue =morphologyDefaultBorderValue()  )

主要参数:src为源图像,dst为形态学操作后的结果图像,element为图像形态学元素单元。anchor默认下为中心位置,iteration为操作的次数

接下来介绍下erode(腐蚀)和dilate(膨胀)的简单原理。

erode:          根据公式可以看出腐蚀便是找出src图像像素点邻域内的最小值来代替该点的像素值。

dilate:            根据公式可以看出膨胀便是找出src图像像素点邻域内的最大值来代替该点的像素值。


4 .Morphology_2.cpp(高级的图像形态学操作)
源码及注释如下:
#include "stdafx.h"    //预编译头文件    /**高级的形态学变换*/#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>using namespace cv;/// 全局变量
Mat src, dst;int morph_elem = 0;
int morph_size = 0;
int morph_operator = 0;
int const max_operator = 4;
int const max_elem = 2;
int const max_kernel_size = 21;const char* window_name = "Morphology Transformations Demo";/** 自定义形态学操作函数声明 */
void Morphology_Operations( int, void* );/*** @主函数*/
int main( int, char** argv )
{/// 加载图片src = imread("D:\\opencv\\lena.png");if( !src.data ){ return -1; }/// 创建窗口namedWindow( window_name, WINDOW_AUTOSIZE );/// 创建选择形态学操作类型的滑动条createTrackbar("Operator:\n 0: Opening - 1: Closing  \n 2: Gradient - 3: Top Hat \n 4: Black Hat", window_name, &morph_operator, max_operator, Morphology_Operations );/// 创建形态学元素类型选择的滑动条createTrackbar( "Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name,&morph_elem, max_elem,Morphology_Operations );/// 创建形态学元素大小选择的滑动条createTrackbar( "Kernel size:\n 2n +1", window_name,&morph_size, max_kernel_size,Morphology_Operations );/// 开始Morphology_Operations( 0, 0 );waitKey(0);return 0;
}/*** @形态学操作函数定义*/
void Morphology_Operations( int, void* )
{// Since MORPH_X : 2,3,4,5 and 6int operation = morph_operator + 2;//创建形态学操作元素Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );/// 形态学操作morphologyEx( src, dst, operation, element );imshow( window_name, dst );
}
运行截图:

这里主要解释函数morphologyEx:C++: void morphologyEx(InputArray src, OutputArray dst, int op, InputArray element, Point anchor=Point(-1,-1), int iterations=1, intborderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() )
这里的参数很多与之前的erode和dilate类似,这里我们主要介绍参数op,op代表要进行的形态学操作,主要包括以下几种:
  • MORPH_OPEN - an opening operation
  • MORPH_CLOSE - a closing operation   
  • MORPH_GRADIENT - a morphological gradient 
  • MORPH_TOPHAT - “top hat”
  • MORPH_BLACKHAT - “black hat”
具体的实现如下图:

比如Opening operation是对src先腐蚀后膨胀的结果,而闭操作是对src先膨胀后腐蚀的结果。其他的操作读者可以自行去实验。


5.Smoothing.cpp(图像平滑(模糊))
源码及注释如下:
#include "stdafx.h"    //预编译头文件    /**图像的模糊*/
#include <iostream>
#include <vector>#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/features2d/features2d.hpp"using namespace std;
using namespace cv;/// 全局变量
int DELAY_CAPTION = 1500;
int DELAY_BLUR = 100;
int MAX_KERNEL_LENGTH = 31;Mat src; Mat dst;
char window_name[] = "Smoothing Demo";/// 函数声明
int display_caption( const char* caption );
int display_dst( int delay );/*** 主函数*/
int main( void )
{namedWindow( window_name, WINDOW_AUTOSIZE );/// 加载图像src = imread( "D:\\opencv\\lena.png", 1 );if( display_caption( "Original Image" ) != 0 ) { return 0; }dst = src.clone();if( display_dst( DELAY_CAPTION ) != 0 ) { return 0; }/// 均匀线性模糊if( display_caption( "Homogeneous Blur" ) != 0 ) { return 0; }for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ){ blur( src, dst, Size( i, i ), Point(-1,-1) );if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }/// 高斯模糊if( display_caption( "Gaussian Blur" ) != 0 ) { return 0; }for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ){ GaussianBlur( src, dst, Size( i, i ), 0, 0 );if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }/// 中值模糊if( display_caption( "Median Blur" ) != 0 ) { return 0; }for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ){ medianBlur ( src, dst, i );if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }/// 双边模糊if( display_caption( "Bilateral Blur" ) != 0 ) { return 0; }for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ){ bilateralFilter ( src, dst, i, i*2, i/2 );if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }display_caption( "End: Press a key!" );waitKey(0);return 0;
}/*** @显示标题*/
int display_caption( const char* caption )
{dst = Mat::zeros( src.size(), src.type() );putText( dst, caption,Point( src.cols/4, src.rows/2),FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) );imshow( window_name, dst );int c = waitKey( DELAY_CAPTION );if( c >= 0 ) { return -1; }return 0;
}/*** @显示图像*/
int display_dst( int delay )
{imshow( window_name, dst );int c = waitKey ( delay );if( c >= 0 ) { return -1; }return 0;
}

运行截图如下:


函数blur原型为:C++: void blur(InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT 
这里主要介绍ksize,ksize代表平滑核元素的大小。该元素为一个矩形像素。其平滑公式为:


关于GaussianBlur,medianBlur和bilateralFilter请读者自行查看:点击打开链接

函数putText原型为:C++: void putText(Mat& img, const string& text, Point org, int fontFace, double fontScale, Scalar color, int thickness=1, int lineType=8, bool bottomLeftOrigin=false )用于在dst图像中生成字符串,参数说明请读者自行参考文档


5.Threshold.cpp(图像阈值)

Demo源码及注释如下:
#include "stdafx.h"    //预编译头文件    /*** 简单的示例代码显示了如何使用不同的阈值*/#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>using namespace cv;/// 全局变量int threshold_value = 0;
int threshold_type = 3;
int const max_value = 255;
int const max_type = 4;
int const max_BINARY_value = 255;Mat src, src_gray, dst;
const char* window_name = "Threshold Demo";const char* trackbar_type = "Type: \n 0: Binary \n 1: Binary Inverted \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted";
const char* trackbar_value = "Value";/// 函数声明
void Threshold_Demo( int, void* );/*** 主函数*/
int main( int, char** argv )
{/// 加载图片src = imread("D:\\opencv\\lena.png", 1 );///将图像转换为灰度图cvtColor( src, src_gray, COLOR_RGB2GRAY );/// 创建窗口namedWindow( window_name, WINDOW_AUTOSIZE );/// 创建阈值类型选择的滑动块createTrackbar( trackbar_type,window_name, &threshold_type,max_type, Threshold_Demo );createTrackbar( trackbar_value,window_name, &threshold_value,max_value, Threshold_Demo );/// 调用阈值函数Threshold_Demo( 0, 0 );/// Wait until user finishes programfor(;;){int c;c = waitKey( 20 );if( (char)c == 27 ){ break; }}}/***阈值函数定义*/
void Threshold_Demo( int, void* )
{/* 0: Binary1: Binary Inverted2: Threshold Truncated3: Threshold to Zero4: Threshold to Zero Inverted*/threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );imshow( window_name, dst );
}
运行截图:


函数threshold原型为:C++: double threshold(InputArray src, OutputArray dst, double thresh, double maxVal, int thresholdType)¶第一个参数为源图像,第二个参数dst为进行阈值转换后的图像,第三个参数thresh为阈值大小,第五个参数thresholdType为阈值类型。
阈值类型及原理如下图所示:



6 .Pyramids.cpp(图像金字塔)

源码及相关注释:
#include "stdafx.h"    //预编译头文件    /**图像金字塔*/#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>using namespace cv;/// 全局变量
Mat src, dst, tmp;const char* window_name = "Pyramids Demo";/**主函数*/
int main( void )
{printf( "\n Zoom In-Out demo  \n " );printf( "------------------ \n" );printf( " * [u] -> Zoom in  \n" );printf( " * [d] -> Zoom out \n" );printf( " * [ESC] -> Close program \n \n" );/// Test image - Make sure it s divisible by 2^{n}src = imread( "D:\\opencv\\chicky_512.png" );if( !src.data ){ printf(" No data! -- Exiting the program \n");return -1; }tmp = src;dst = tmp;/// 创建窗口namedWindow( window_name, WINDOW_AUTOSIZE );imshow( window_name, dst );/// Loopfor(;;){int c;c = waitKey(1000);if( (char)c == 27 ){ break; }if( (char)c == 'u' ){ pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 ) );printf( "** Zoom In: Image x 2 \n" );}else if( (char)c == 'd' ){ pyrDown( tmp, dst, Size( tmp.cols/2, tmp.rows/2 ) );printf( "** Zoom Out: Image / 2 \n" );}imshow( window_name, dst );tmp = dst;}return 0;
}
运行截图如下:

pyrUp函数原型:C++: void pyrUp(InputArray src, OutputArray dst, const Size& dstsize=Size())
pyrDown函数原型:C++: void pyrDown(InputArray src, OutputArray dst, const Size& dstsize=Size())


OK,ImgProc(图像处理)就介绍到此。


这篇关于OpenCV2.4.10之samples_cpp_tutorial-code_learn-----ImgProc(图像处理)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1104643

相关文章

Debugging Lua Project created in Cocos Code IDE creates “Waiting for debugger to connect” in Win-7

转自 I Installed Cocos Code IDE and created a new Lua Project. When Debugging the Project(F11) the game window pops up and gives me the message waiting for debugger to connect and then freezes. Also a

参会邀请 | 第二届机器视觉、图像处理与影像技术国际会议(MVIPIT 2024)

第二届机器视觉、图像处理与影像技术国际会议(MVIPIT 2024)将于2024年9月13日-15日在中国张家口召开。 MVIPIT 2024聚焦机器视觉、图像处理与影像技术,旨在为专家、学者和研究人员提供一个国际平台,分享研究成果,讨论问题和挑战,探索前沿技术。诚邀高校、科研院所、企业等有关方面的专家学者参加会议。 9月13日(周五):签到日 9月14日(周六):会议日 9月15日(周日

LLVM入门2:如何基于自己的代码生成IR-LLVM IR code generation实例介绍

概述 本节将通过一个简单的例子来介绍如何生成llvm IR,以Kaleidoscope IR中的例子为例,我们基于LLVM接口构建一个简单的编译器,实现简单的语句解析并转化为LLVM IR,生成对应的LLVM IR部分,代码如下,文件名为toy.cpp,先给出代码,后面会详细介绍每一步分代码: #include "llvm/ADT/APFloat.h"#include "llvm/ADT/S

类模板中.h和.cpp的实现方法

一般类的声明和实现放在两个文件中,然后在使用该类的主程序代码中,包含相应的头文件".h"就可以了,但是,模板类必须包含该其实现的.cpp文件才行。也就是说,在你的主程序中,将 #include"DouCirLList.h" 替换成 #include"DouCirLList.cpp" 应该就可以了。 在使用类模板技术时,可在.h中实现,也可在.h和.cpp中分开实现,若用.h实

VS Code 调试go程序的相关配置说明

用 VS code 调试Go程序需要在.vscode/launch.json文件中增加如下配置:  // launch.json{// Use IntelliSense to learn about possible attributes.// Hover to view descriptions of existing attributes.// For more information,

Learn ComputeShader 09 Night version lenses

这次将要制作一个类似夜视仪的效果 第一步就是要降低图像的分辨率, 这只需要将id.xy除上一个数字然后再乘上这个数字 可以根据下图理解,很明显通过这个操作在多个像素显示了相同的颜色,并且很多像素颜色被丢失了,自然就会有降低分辨率的效果 效果: 但是这样图像太锐利了,我们加入噪声去解决这个问题 [numthreads(8, 8, 1)]void CSMain(uint3 id

CPP中的hash [more cpp-7]

写在前面 hash 在英文中是弄乱的含义。在编程中,hash是一种数据技术,它把任意类型的数据通过算法,生成一串数字(hash code),实现hash的函数称为哈希函数,又称散列函数,杂凑函数。在CPP中hashcode是一个size_t类型的数字。 你可能会问?把数据弄乱有什么用?为什么我们要把数据映射到一串数字上?这又什么意义吗?我们先看看hash的性质 一般hash性质 唯一性(唯

code: 400, msg: Required request body is missing 错误解决

引起这个错误的原因是,请求参数按照get方式给。 应该给json字符串才对 补充: 1. @RequestBody String resource 加@RequestBody必须给json字符串,否则会报错400,记如标题错误。 不加这个的进行请求的话,其实post和get就没有什么区别了。 2. List<String> indexCodes=(List<String>)json.

iOS项目发布提交出现invalid code signing entitlements错误。

1、进入开发者账号,选择App IDs,找到自己项目对应的AppId,点击进去编辑, 2、看下错误提示出现  --Specifically, value "CVYZ6723728.*" for key "com.apple.developer.ubiquity-container-identifiers" in XX is not supported.-- 这样的错误提示 将ubiquity

【最新华为OD机试E卷-支持在线评测】机器人活动区域(100分)多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-E/D卷的三语言AC题解 💻 ACM金牌🏅️团队| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线评测,专栏文章质量平均 94 分 最新华为OD机试目录: https://blog.