首页 > 其他分享 >OpenCV 学习之旅

OpenCV 学习之旅

时间:2023-06-04 17:12:47浏览次数:48  
标签:plt 之旅 img imshow 学习 OpenCV 图像 阈值 cv

OpenCV 学习之旅

​ 话说已经有一周没见面了,勇士们每天都聚集在我的门前敲门,请求我出山,可是我仍然忙于我的AI大作业,操作系统实验和信号与系统实验,简称三座大山。看在你们的情真意切,周末抽出一点时间帮助你们解决公主布置的问题。

​ 上回说到IU公主想要比OpenCV招胥,到底谁能成为贤胥呢?

Chapter 3

3.1 图像的基本操作

访问和修改像素值

​ 大家应该从IU公主那里听说了,图像其实是一个矩阵,我们可以通过行和列来访问像素值,对于一个BGR图像,它返回一个由蓝色、绿色和红色组成的数组。对于灰度图像,只返回相应的灰度。

img = cv.imread('iu.jpg')
px = img[100, 100]
print(px)

# 仅访问红色像素
red = img[100, 100, 2]
print(red)

​ 上述代码输出结果为:

[182 158 160]
160

​ 我们也可以对某个位置的像素进行修改:

img[100, 100] = [255, 255, 255]

访问图像属性

​ 图像属性包括行数,列数和通道数,图像数据类型,像素数等。

​ 图像的形状可通过img.shape来访问,它将返回行,列和通道数的元组。

print(img.shape)
# 程序输出结果(827, 828, 3)

​ 这个结果表明图像827行,828列,3通道,如果图像是灰度,则只会有两个数据,无灰度。这个函数可以用来区别一个图片是彩色还是灰度。

print(img.size)
# 2054268

img.size函数用来访问像素总数,img.dtype函数用来访问图像的数据类型。

print(img.dtype)
# uint8

图像感兴趣区域ROI

​ 对于某位勇士的照片,IU公主往往只关注这位勇士的脸庞是否英骏,所以她需要一位掌握选择人脸区域的勇士作为配偶。

ball = img[280:340, 330:390]
img[273:333, 100:160] = ball

cv.imshow('messi', img)
cv.waitKey(0)
cv.destroyAllWindows()

​ 这位勇士将梅西脚下的球从一个变成两个,IU公主听了直摇头(dogshake.jpg)。

拆分和合并图像通道

​ 我们有时候可能要单独处理图像的R,G,B通道,所以我们将BGR图像拆分为单个通道,并将这些单独的频道加入BGR图片,代码如下:

b, g, r = cv.split(img)
img = cv.merge((b, g, r))

b = img[:, :, 0]

# 将所有红色像素置0,无需拆分通道
img[:, :, 2] = 0

​ 由于IU公主是个大忙人,所以IU公主对各项时间性能指标都非常看重,像split这种操作非常耗时,IU公主告诉你要谨慎使用~

为图像设置边框(填充)

​ IU公主是个讲究的主,所以她希望和她有关的照片都被装裱~

​ 想要在图像周围创建边框,可以使用cv.copyMakeBorder()函数,它在卷积运算和零填充等方面有更多的应用。该函数的参数如下:

src:输入图像。

top,bottom,left,right:边界宽度

borderType:边框的类型,如下:

cv.BORDER_CONSTANT:添加恒定的彩色边框,该值应作为下一个参数给出。

cv.BORDER_REFLECT:边框将是边框元素的镜像。fedcba|abcdefgh|hgfedcba

value:边框颜色,如果边框类型为cv.BORDER_CONSTANT

示例代码如下:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

BLUE = [255,0,0]
img1 = cv.imread('opencv-logo.jpg')
replicate = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REPLICATE)
reflect = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT)
reflect101 = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT_101)
wrap = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_WRAP)
constant= cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_CONSTANT,value=BLUE)
plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL')
plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE')
plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT')
plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101')
plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP')
plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT')
plt.show()

3.2 图像上的算数运算

在神光圣殿,女王IU有自己一套治国理政的方略~

图像加法

​ 图像的基本运算包括加法,减法,按位运算等。其中OpenCV的加法与numpy的加法有区别,OpenCV的加法是饱和运算,而Numpy加法是模运算。我们可以使用OpenCV函数cv.add()或者通过numpy操作res=img1+img2添加两个图像。需要注意的是,两个图像应具有相同的深度和类型,或者第二个图像可以只是一个标量值。

import numpy as np
import cv2 as cv

x = np.uint8([250])
y = np.uint8([10])

print(cv.add(x, y))
print(x+y)

​ 如下面这段程序,输出结果如下:

[[255]]
[4]

图像融合

​ IU女王十分喜欢OpenCV,想和OpenCV的logo融为一体,所以她给勇士们的第2道题是把IU女王的照片和OpenCV的logo融合~,身为勇士的你,既想博得女王的芳心,又想抢先其他勇士,于是你找到了我。

​ 图像融合也是图像的加法,但是对图像赋予了不同的权重,效果是有融合或透明的感觉。公式如下:
$$
G(X)=(1-\alpha)f_0(x)+\alpha f_1(x)
$$
​ 你学会了这个公式之后,你开始动手融合图像,使用cv.addWeighted()函数,代码如下:

iu = cv.imread('iu.jpg')
opencv = cv.imread('opencv-logo.jpg')

# 调整图像大小(如果需要)
opencv = cv.resize(opencv, (iu.shape[1], iu.shape[0]))
dst = cv.addWeighted(iu, 0.7, opencv, 0.3, 0)

# 显示融合后的图像
cv.imshow('Blended Image', dst)
cv.waitKey(0)
cv.destroyAllWindows()

按位运算

​ 包括AND,OR,NOT,XOR等操作,我们学习如何改变一个图像的特定区域。我想把opencv的标志放在一个图像上面。如果我添加两个图像,它会改变颜色,如果我混合它,我得到一个透明的效果。但我不希望它是透明的,如果是一个矩形区域,我可以使用ROI,但是opencv的logo不是矩形,所以我们可以用按位操作实现。

习题

​ 使用 cv.addWeighted 函数在文件夹中创建图像的幻灯片放映,并在图像之间进行平滑过渡。

# 读取图像文件
img1 = cv.imread('iu.jpg')
img2 = cv.imread('messi5.jpg')

# 确保两个图像具有相同的尺寸
img1 = cv.resize(img1, (800, 600))
img2 = cv.resize(img2, (800, 600))

# 定义过渡参数
alpha = 0.0

# 创建窗口用于显示结果
cv.namedWindow('Slideshow', cv.WINDOW_NORMAL)

# 循环进行过渡和显示图像
while True:
    # 根据过渡参数计算混合图像
    blend = cv.addWeighted(img1, 1 - alpha, img2, alpha, 0)

    # 显示混合图像
    cv.imshow('Slideshow', blend)

    # 通过修改过渡参数实现平滑过渡
    alpha += 0.01

    # 如果过渡参数超过范围,退出循环
    if alpha >= 1.0:
        break

    # 等待一段时间,控制过渡速度
    cv.waitKey(50)

# 等待按键关闭窗口
cv.waitKey(0)
cv.destroyAllWindows()

3.3 性能衡量和提升技术

​ 征服iu女王,需要有最快的速度~

使用OpenCV衡量性能

cv.getTickCount函数返回从参考时间到调用函数那一刻之间的时钟周期数。因此,如果在函数执行之前和之后调用它,则会获得用于执行函数的时间周期数。

cv.getTickFrequency函数返回时钟周期频率或每秒的时钟周期数。因此,要找到执行时间(以秒位单位),代码如下:

import cv2 as cv


e1 = cv.getTickCount()
# 你的执行代码
e2 = cv.getTickCount()
time = (e2 - e1) / cv.getTickFrequency()
print(time)
# 2.9e-06

​ 用中位数滤波,测试时间:

import cv2 as cv


img1 = cv.imread('messi5.jpg')
e1 = cv.getTickCount()
for i in range(5,49,2):
    img1 = cv.medianBlur(img1, i)
e2 = cv.getTickCount()
t = (e2 - e1)/cv.getTickFrequency()
print(t)
# 0.289932

OpenCV中的默认优化

​ 许多OpenCV函数都是使用SSE2,AVX等进行优化的。它还包含未优化的代码。我们可以使用cvUseoptimized检查是否启用/禁用和cvSetuseoptimized以启用/禁用它。

在IPython中衡量性能

​ IPython提供了一个神奇的命令计时器来执行操作。且OpenCV的速度远比numpy的快。

Chapter 4

​ iu女王希望神光圣殿是光芒万丈的,而不是一片死灰~

4.1 改变颜色空间

改变颜色空间

​ 我们重点研究两个最广泛使用的BGR->灰色和BGR->HSV。对于颜色转换,我们使用cv函数,cvtColor(input_image,flag),其中flag决定转换类型。BGR->灰度转换,我们使用标志cv.COLOR_BGR2GRAY。类似地,对于BGR->HSV,我们使用标志cv.COLOR_BGR2HSV。

OpenCV中HSV颜色模型及颜色分量范围 - 知乎 (zhihu.com)

对象追踪

​ HSV的色相范围为[0,179],饱和度范围为[0,255],值范围为[0,255]。不同的软件使用不同的规模。因此,如果要将OpenCV值和它们比较,需要将这些范围标准化。

​ 我们准备提取一个有颜色的对象,在HSV中比在BGR颜色空间中更容易表示颜色,

import cv2 as cv
import numpy as np

img = cv.imread('ball.png')
img = cv.resize(img, (640, 480))
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)

# 定义HSV中蓝色的范围
lower_yellow = np.array([26, 43, 46])
upper_yellow = np.array([34, 255, 255])

# 设置HSV的阈值使得只取蓝色
mask = cv.inRange(hsv, lower_yellow, upper_yellow)
# 将掩膜和图像逐像素叠加
res = cv.bitwise_and(img, img, mask=mask)


cv.imshow('src', img)
cv.imshow('mask', mask)
cv.imshow('res', res)
cv.waitKey(0)
cv.destroyAllWindows()





如何找到要追踪的HSV值?

​ 如果想要查找绿色的HSV值,代码如下:

hsv_green = cv.cvtColor(green,cv.COLOR_BGR2HSV)

习题

​ iu女王可不单单喜欢某种颜色,她同时喜欢了多种颜色,所以请你提取出opencv-logo中的红,绿,蓝三种颜色的图形。

import cv2 as cv
import numpy as np

img = cv.imread('opencv-logo.jpg')
img = cv.resize(img, (640, 480))
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)

# 定义HSV中蓝色的范围
lower_red = np.array([0, 43, 46])
upper_red = np.array([10, 255, 255])

lower_green = np.array([35, 43, 46])
upper_green = np.array([77, 255, 255])

lower_blue = np.array([100, 43, 46])
upper_blue = np.array([124, 255, 255])

# 设置HSV的阈值使得只取蓝色
mask_red = cv.inRange(hsv, lower_red, upper_red)
mask_green = cv.inRange(hsv, lower_green, upper_green)
mask_blue = cv.inRange(hsv, lower_blue, upper_blue)
mask_combined = cv.bitwise_or(mask_red, cv.bitwise_or(mask_green, mask_blue))
# 将掩膜和图像逐像素叠加
res = cv.bitwise_and(img, img, mask=mask_combined)


cv.imshow('src', img)
cv.imshow('res', res)
cv.waitKey(0)
cv.destroyAllWindows()

4.2 图像的几何变换

​ iu女王对几何学相当感兴趣,致力于研究OpenCV上的平移,旋转,仿射变换等。

变换

​ OpenCV提供了两个转换函数cv.warpAffinecv.warpPerspective。其中cv.warpAffine采用$23$转换矩阵,而cv.warpPerspective采用$33$转换矩阵作为输入。

缩放

​ 缩放主要是调整图像的大小,OpenCV有一个resize函数,其实这个函数我们在之前也见过,就是要做图像加法的时候,由于两个图像的大小不一样,我们用resize函数进行调整。

​ 图像的大小可以手动指定,也可以指定放缩比例。或者使用不同的插值方法,首选的插值方法是cv.INTER_AREA用于缩小,cv.INTER_CUBICcv.INTER_LINEAR用于缩放。默认情况下,出于所有调整大小的目的,使用的插值方法为cv.INTER_LINEAR

import cv2 as cv
import numpy as np

img = cv.imread('messi5.jpg')
cv.imshow('src', img)
# fx和fy是缩放因子
img = cv.resize(img, None, fx=1, fy=1, interpolation=cv.INTER_CUBIC)

# 或者
height, width = img.shape[:2]
res = cv.resize(img, (2*width, 2*height), interpolation=cv.INTER_CUBIC)
cv.imshow('dst', img)
cv.imshow('res', res)
cv.waitKey(0)
cv.destroyAllWindows()

平移

​ 平移是物体位置的移动,假设在(x,y)方向上的位移是(tx,ty),可以通过转换矩阵$\mathbf{M}$,如下所示:
$$
\begin{matrix}
1&0&t_x\
0&1&t_y\
\end{matrix}
$$
​ 我们可以把这个矩阵放入np.float32类型的numpy数组中,并传递给cv.warpAffine函数。

旋转

​ 图像旋转角度$\theta$是通过以下形式的变换矩阵实现的:
$$
\begin{matrix}
cos\theta&-sin\theta\
sin\theta&cos\theta\
\end{matrix}
$$
​ 但是OpenCV提供了可缩放的旋转以及可调整的旋转中心,因此,我们可以在自己选定的任何位置旋转,修改后的变换矩阵为:
$$
\begin{matrix}
\alpha&\beta&(1-\alpha)center.x-\betacentery\
-\beta&\alpha&\beta
center.x+(1-\alpha)center.y
\end{matrix}
$$
其中:
$$
\alpha=scale
cos\theta\
\beta=scale*sin\theta

$$
​ 为了找到这个转换矩阵,OpenCV提供了一个函数cv.getRotationMatrix2D。示例代码如下:

import cv2 as cv
import numpy as np

img = cv.imread('messi5.jpg', 0)
rows, cols = img.shape
# 平移
# M = np.float32([[1, 0, 100], [0, 1, 50]])
# 旋转 center + angle + scale
M = cv.getRotationMatrix2D(((cols-1)/2.0, (rows-1)/2.0), 90, 1)
dst = cv.warpAffine(img, M, (cols, rows))
cv.imshow('dst', dst)
cv.waitKey(0)
cv.destroyAllWindows()

仿射变换

​ 在仿射变换中,原始图像中的所有平行线在输出图像仍然平行。为了找到变换矩阵,我们需要输入图像中的三个点及其在输出图像中的对应位置。然后cv.getAffineTransform将创建一个2*3矩阵,该矩阵将传递给cv.warpAffine

img = cv.imread('drawing.png')
rows,cols,ch = img.shape
pts1 = np.float32([[50,50],[200,50],[50,200]])
pts2 = np.float32([[10,100],[200,50],[100,250]])
M = cv.getAffineTransform(pts1,pts2)
dst = cv.warpAffine(img,M,(cols,rows))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')

透视变换

​ 对于透视变换,我们需要$33$变换矩阵。即使在转换后,直线也将保持直线。要找到此变换矩阵,我需要在输入图像上有4个点,在输出图像上需要相应的点。在这四个点中,其中三个不应共线。然后可以通过函数cv.getPerspectiveTransform找到变换矩阵。然后将cv.warpPerspective应用于此$33$转换矩阵。

import matplotlib.pyplot as plt
import numpy as np


img = cv.imread('sudoku.jpg')
rows, cols, ch = img.shape
pts1 = np.float32([[56, 65], [368, 52], [28, 387], [389, 390]])
pts2 = np.float32([[0, 0], [300, 0], [0, 300], [300, 300]])
M = cv.getPerspectiveTransform(pts1, pts2)
dst = cv.warpPerspective(img, M, (300, 300))
plt.subplot(121), plt.imshow(img), plt.title('Input')
plt.subplot(122), plt.imshow(dst), plt.title('Output')
plt.show()

4.3 图像阈值

简单阈值

​ 对于每个像素,应用相同的阈值。如果像素值小于阈值,则将其设置为0,否则设置为最大值。函数cv.threshold用于应用阈值。第一个参数是源图像,它应该是灰度图像。第二个参数是阈值,用于对像素值进行分类。第三个参数是分配给超过阈值的像素值的最大值。OpenCV提供了不同类型的阈值,这由函数的第四个参数给出。通过使用cv.THRESH_BINARY类型,所有简单的阈值类型有:cv.THRESH_BINARYcv.THRESH_BINARY_INVcv.THRESH_TRUNC,cv.THRESH_TOZERO,cv.THRESH_TOZERO_INV

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

img = cv.imread('gradient.png', 0)
ret1, thresh1 = cv.threshold(img, 127, 255, cv.THRESH_BINARY)
ret2, thresh2 = cv.threshold(img, 127, 255, cv.THRESH_BINARY_INV)
ret3, thresh3 = cv.threshold(img, 127, 255, cv.THRESH_TRUNC)
ret4, thresh4 = cv.threshold(img, 127, 255, cv.THRESH_TOZERO)
ret5, thresh5 = cv.threshold(img, 127, 255, cv.THRESH_TOZERO_INV)
titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in range(6):
    plt.subplot(2, 3, i+1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

自适应阈值

​ 简单阈值我们是使用一个全局值作为阈值,但是如果图像在不同区域具有不同的光照条件,这种情况下,自适应阈值阈值化可以提供帮助。在此,算法基于像素周围的小区确定像素的阈值。因此,对于同一图像的不同区域,我们获得不同的阈值,这为光照度变化的图像提供了更好的结果。

​ 除上述参数外,方法cv.adaptiveThreshold还包括三个输入参数:

adaptiveMethod决定阈值是如何计算的:

cv.ADAPTIVE_THRESH_MEAN_C:阈值是邻近区域的平均值减去常数C

cv.ADAPTIVE_THRESH_GAUSSIAN_C:阈值是邻域值的高斯加权总和减去常数C

BLOCKSIZE确定附近区域的大小,C是从邻域像素的平均或加权总和中减去的一个常数C

调用格式:

void adaptiveThreshold( InputArray src, OutputArray dst,
                       double maxValue, int adaptiveMethod,
                       int thresholdType, int blockSize, double C );
  • src表示需要进行二值化的图像;需要注意的是,该输入必须是8-bit单通道的图像;
  • dst表示输出图像的二值图像;
  • maxValue是一个非零值,用于对哪些满足条件的阈值进行赋值;
  • adaptiveMethod表示选择哪一种自适应阈值算法;Opencv提供两种,ADAPTIVE_THRESH_MEAN_CADAPTIVE_THRESH_GAUSSIAN_C,下面会详细介绍;
  • thresholdType表示二值化类型,OpenCV提供两种, THRESH_BINARYTHRESH_BINARY_INV,下面会详细介绍;
  • blocksize表示参与计算的像素的领域范围,必须使用奇数;
  • C可以为正数, 零或者负数;用于在计算过程中容忍程度;

下面代码比较了光照变化的图像的全局阈值和自适应阈值:

import cv2 as cv
import numpy as np

img = cv.imread('sudoku.jpg', 0)
# C感觉有点调亮图片的作用,
thresh1 = cv.adaptiveThreshold(img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 25, 2)
ret1, thresh2 = cv.threshold(img, 127, 255, cv.THRESH_BINARY)
cv.imshow('Adaptive Mean Thresholding', thresh1)
cv.imshow('Simple Thresholding', thresh2)
cv.waitKey(0)
cv.destroyAllWindows()



Otsu的二值化

​ 在全局阈值化中,我们使用任意选择的值作为阈值,相反,Otsu的方法避免了必须选择一个值并自动确定它。考虑仅具有两个不同图像值的图像,其中直方图仅包含两个峰,一个好的阈值应该在这两个值中间,类似的,Otsu的方法从图像直方图中确定最佳全局阈值。

​ 因此,使用cv.threshold作为附加标志传递。阈值可以任意选择,然后,算法找到最佳阈值,该阈值作为第一输出返回。

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('noisy2.png',0)
# 全局阈值
ret1,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
# Otsu阈值
ret2,th2 = cv.threshold(img,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
# 高斯滤波后再采用Otsu阈值
blur = cv.GaussianBlur(img,(5,5),0)
ret3,th3 = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
# 绘制所有图像及其直方图
images = [img, 0, th1,
          img, 0, th2,
          blur, 0, th3]
titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
          'Original Noisy Image','Histogram',"Otsu's Thresholding",
          'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]
for i in range(3):
    plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')
    plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)
    plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')
    plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
plt.show()

标签:plt,之旅,img,imshow,学习,OpenCV,图像,阈值,cv
From: https://www.cnblogs.com/chickchick/p/17455883.html

相关文章

  • CSS Position学习
    介绍CSSPosition有四个属性:[color=darkblue]relativeabsolutefixedstatic(默认)[/color]样例<divid="parent"><divid="sub1">sub1</div><divid="sub2">sub2</div></div>sub1和sub2是同级关系,parent是它们的父......
  • 【学习笔记】(18) 长链剖分
    长链剖分1.算法简介与性质长链剖分本质上就是另外一种链剖分方式。长链剖分与重链剖分有相通之处,后者是将子树大小最大的儿子作为重儿子,前者则是将子树深度最大的儿子作为重儿子。可见两者只是换了一个剖分形式。长链剖分有如下性质:性质1:每个节点所在长链末端为其子树......
  • 【学习笔记】(14) 初等数论(一)
    1.【最大公约数(GCD)和最小公倍数(LCM)】【基本性质、定理】\(\largegcd(a,b)=gcd(b,a−b)(a>b)\)\(\largegcd(a,b)=gcd(b,a\)\(\largemod\)\(b)\)\(\largegcd(a,b)\)\(\largelcm(a,b)=ab\)【推导结论】\(\largek|gcd(a,b)⟺k|a\)且\(k|b\)\(\larg......
  • babylon.js 学习笔记(9)
    继续学习sprite用法,做为一个游戏引擎,怎能没有Sprite(精灵),下面是基本示例:constcreateScene=function(){constscene=newBABYLON.Scene(engine);constcamera=newBABYLON.ArcRotateCamera("Camera",-Math.PI/2,Math.PI/2,8,newBA......
  • Maven2之旅
    关于Maven2的系列文章我的Maven2之旅:一.前言,准备及安装.摘要:Maven2的介绍及安装阅读全文[url]http://www.blogjava.net/sitinspring/archive/2007/06/18/125006.html[/url]我的Maven2之旅:二.Maven常用命令摘要:Maven常用命令阅读全文[url]http://www.blogjava.net......
  • google gson学习
    [color=red][b]googlegson学习[/b][/color][url]http://lyking2001.iteye.com/blog/504156[/url]Gson网址http://code.google.com/p/google-gson/[b]1.简单的处理list和map[/b]Gsongson=newGson();ListtestList=newArrayList();testList.a......
  • dubbo源码学习(四)初始化过程细节:解析服务
    今天将真正去看dubbo内部的实现过程,看dubbo的源码前我先把dubbo的用户指南和开发指指南大概的看了一遍,这样再看dubbo源码比较轻松。从用户指南和开发指指南可以找到相应的切入点,今天将介绍的是dubbo的初始化解析bean的过程:解析服务基于dubbo.jar内的META......
  • dubbo源码学习(二) : spring 自定义标签
    做dubbo的配置时很容易发现,dubbo有一套自己的标签,提供给开发者配置,其实每一个标签对应着一个实体,在容器启动的时候,dubbo会对所有的配置进行解析然后将解析后的内容设置到实体里,最终dubbo会根据实体中的值生成贯穿全局的统一URL。利用自定义标签使配置简单明......
  • 极客时间--golang并发编程实战课--Mutex学习总结
    互斥锁的实现机制互斥锁是并发控制的一个手段,是为了避免竞争而建立的一种并发控制机制。在并发编程中,如果程序中的一部分会被并发访问或修改,那么,为了避免并发访问导致的意想不到的结果,这部分程序需要被保护起来,这部分被保护起来的程序,就叫做临界区。可以说,临界区就是一个被共......
  • 深入学习ThreadLocal
    1、用来干吗的?用于线程在任意的地方去共享数据,而不被其他线程所干扰,2、原理是什么因为每个线程维护一份ThreadLocalMap,使用threadlocal.set(obj)方法是存放在map里面的Entry<<WeekReference>ThreadLocal,Value>数组里3、实际案例,比如写了util类,但是SimplateDateFormate是线程......