2019-01-18 16:18:53 qq_34814092 阅读数 196

Java OpenCV-4.0.0 图像处理17 像素重映射

Java OpenCV-4.0.0 像素重映射(remap)

图像的坐标映射是通过原图像与目标图像之间建立一种映射关系,这种映射关系有两种,一种是计算原图像任意像素在映射后图像的坐标位置,另一种是计算变换后图像任意像素反映射在原图像的坐标位置。

opencv中提供重映射等操作,其中重映射就是把一幅图像中某位置的像素放置到另一个图片指定位置的过程。为了完成映射过程,需要获得一些插值为非整数像素的坐标。对于原图像和目标图像,满足下式:

G(x,y)=f(h(x,y))

G()是目标图像,f()是源图像,而h(x,y)是作用于(x,y)的映射方法函数。

简单点说就是把输入图像中各个像素按照一定的规则映射到另外一张图像的对应位置上去,形成一张新的图像。

package com.xu.image;

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

/**  
 * 
 * @Title: Image.java   
 * @Description: OpenCV-4.0.0 测试文件
 * @Package com.xu.test   
 * @author: xuhyacinth     
 * @date: 2019年7月10日12:13:13   
 * @version: V-1.0.0 
 * @Copyright: 2019 xuhyacinth
 *
 */
public class Image {

	static {
		//在使用OpenCV前必须加载Core.NATIVE_LIBRARY_NAME类,否则会报错
		System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
	}

	public static void main(String[] args) {
		remape(1);
	}

	/**
	 * OpenCV-4.0.0 自定义图像重映射 
	 * <table border="1" cellpadding="8"> 
	 * <tr><th>输入参数</th><th>参数解释</th></tr> 
	 * <tr><td align="center">0</td><td>缩小为原来的1/2</td></tr> 
	 * <tr><td align="center">1</td><td>上下对调(X轴对称)</td></tr> 
	 * <tr><td align="center">2</td><td>左右对调(Y轴对称)</td></tr> 
	 * <tr><td align="center">3</td><td>上下左右对调(XY轴对称)</td></tr> 
	 * <tr><td colspan="2">注:G(x,y)=f(h(x,y)),重映射的Mat必须为8位单通道灰度图片</td></tr> 
	 * </table>
	 * @param type 图片变换方式 (0,1,2,3)
	 * @return: void 
	 * @date: 2019年7月10日 上午12:53:37
	 */
	public static void remape(int type) {
		Mat src = Imgcodecs.imread("C:\\Users\\xuhya\\Pictures\\99.jpg");
		Mat dst=new Mat();
		Mat xmat = new Mat(src.size (),CvType.CV_32FC1);//8位单通道灰度图片
		Mat ymat = new Mat(src.size (),CvType.CV_32FC1);//8位单通道灰度图片
		for (int i = 0, rlen = src.rows(); i < rlen; i++) {
			for (int j = 0, clen = src.cols(); j < clen; j++) {
				switch (type) {
				case 0://0 缩小为原来的1/2
					if (i > clen * 0.25 && i < clen * 0.75 && j > rlen * 0.25 && j < rlen * 0.75)  {
						xmat.put(i,j,2*(j-clen*0.25));
						ymat.put(i,j,2*(i-rlen*0.25));
					} else {
						xmat.put(i,j,255);
						ymat.put(i,j,255);
					}
					break;
				case 1://1 上下对调(X轴对称)
					xmat.put(i,j,j);
					ymat.put(i,j,rlen-i-1);
					break;
				case 2://2 左右对调(Y轴对称)
					xmat.put(i,j,clen-j-1);
					ymat.put(i,j,i);
					break;
				case 3://3 上下左右对调(XY轴对称)
					xmat.put(i,j,clen-j-1);
					ymat.put(i,j,rlen-i-1);
					break;
				default:
					break;
				}
			}
		}
		Imgproc.remap (src,dst,xmat,ymat,Imgproc.CV_BILATERAL,Imgproc.CV_BLUR,new Scalar(0, 0, 0));
		HighGui.imshow("自定义图像重映射", dst);
		HighGui.waitKey(0);
	}

	/**
	 * OpenCV-4.0.0 自定义像素映射
	 * <table border="1" cellpadding="8">
	 * <tr><th>输入参数</th><th>参数解释</th></tr>
	 * <tr><td align="center">1</td><td>上下旋转</td></tr>
	 * <tr><td align="center">2</td><td>左右旋转</td></tr>
	 * </table>
	 * @param type 旋转方向
	 * @return: void
	 * @date: 2019年7月10日 下午12:25:00
	 */
	public static void myRemap(int type) {
		Mat src=Imgcodecs.imread("C:\\Users\\Administrator\\Pictures\\55.jpg");
		Mat dst = new Mat(src.size(), src.type());
		for (int i = 0, rlen = src.rows(); i < rlen; i++) {
			for (int j = 0, clen = src.cols(); j < clen; j++) {
				if (type==1) {
					dst.put(i, j, src.get(rlen-i-1, j).clone());
				}else if (type==2) {
					dst.put(i, j, src.get(i, clen-j-1).clone());
				}
			}
		}
		HighGui.imshow("自定义图像重映射", dst);
		HighGui.waitKey(0);
	}

}


2017-02-13 10:27:21 u010303389 阅读数 951

像素间的基本关系

4邻域

一幅图像中,位于坐标(x,y)处的像素p有4个相邻的像素,分别位于其上下左右,其坐标如下:

(x+1,y)、(x-1,y)、(x,y+1)、(x,y-1)

用N4(p)表示像素p的4邻域



4邻域示意图

D邻域

像素p(x,y)的D邻域就是这个像素点的四个顶点对应的点,坐标如下:

(x+1,y+1)、(x+1,y-1)、(x-1,y+1)、(x-1,y-1)

用ND(p)表示像素p的D邻域:



D邻域示意图

8邻域

像素p(x,y)的8邻域就是这个像素的4邻域的点+ D邻域的点

用N8(p)表示像素p的8邻域:N8(p) = N4(p) + ND(p)



8邻域示意图
2017-07-16 21:37:32 webzhuce 阅读数 2587
图像像素值的访问与修改是最常用的一种操作。VTK提供了两种访问图像像素值的访问。

一、直接访问

  第一种方法是直接发访问vtkImageData的数据数组。vtkImageData提供了GetScalarPointer()函数获取数据数组指针,该函数有三种形式:

virtual void* GetScalarPointer(int coordinates[3]);
virtual void* GetScalarPointer(int x, int y, int z);
virtual void* GetScalarPointer();

前两种形式根据给定的像素索引得到指定的像素值,注意返回的是第(x,y,z)个像素值的地址。而第三种形式是返回图像数据数组的头指针,然后根据头指针可以依次访问索引像素。

示例演示

使用GetScalarPointer遍历图像像素。

CMakeLists.txt代码

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(VisitImagePixelDirectlyExample)
FIND_PACKAGE(VTK REQUIRED)
INCLUDE(${VTK_USE_FILE})
ADD_EXECUTABLE(VisitImagePixelDirectlyExample   VisitImagePixelDirectlyExample.cpp)
TARGET_LINK_LIBRARIES(VisitImagePixelDirectlyExample ${VTK_LIBRARIES})

VisitImagePixelDirectlyExample.cpp文件代码如下:

/**********************************************************************

文件名: VisitImagePixelDirectlyExample.cpp
Copyright (c) 阿Bin先生. All rights reserved.
更多信息请访问: http://blog.csdn.net/webzhuce

**********************************************************************/

#include <vtkSmartPointer.h>
#include <vtkImageViewer2.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkBMPReader.h>
#include <vtkImageData.h>

int main(int argc, char* argv[])
{
    vtkSmartPointer<vtkBMPReader> reader =
        vtkSmartPointer<vtkBMPReader>::New();
    //测试图像:E:\TestData\masonry.bmp
    reader->SetFileName("E:\\TestData\\masonry.bmp");
    reader->Update();

    int dims[3];
    reader->GetOutput()->GetDimensions(dims);

    int nbOfComp;
    nbOfComp = reader->GetOutput()->GetNumberOfScalarComponents();

    for(int k=0; k<dims[2]; k++)
    {
        for(int j=0; j<dims[1]; j++)
        {
            for(int i=0; i<dims[0]; i++)
            {
                if(i<100 && j<100)
                {
                    unsigned char * pixel = 
                        (unsigned char *) ( reader->GetOutput()->GetScalarPointer(i, j, k) );
                    *pixel = 0;
                    *(pixel+1) = 0;
                    *(pixel+2) = 0;
                }
            }
        }
    }

    vtkSmartPointer<vtkImageViewer2> imageViewer =
        vtkSmartPointer<vtkImageViewer2>::New();
    imageViewer->SetInputConnection(reader->GetOutputPort());

    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
    imageViewer->SetupInteractor(renderWindowInteractor);
    imageViewer->Render();
    imageViewer->GetRenderer()->ResetCamera();
    imageViewer->Render();

    imageViewer->GetRenderer()->SetBackground(1.0, 1.0, 1.0);
    imageViewer->SetSize(640, 480);
    imageViewer->GetRenderWindow()->SetWindowName("VisitImagePixelDirectlyExample");


    renderWindowInteractor->Start();

    return EXIT_SUCCESS;
}

运行结果:

这里写图片描述

  示例实现了将图像的100*100大小的区域设置为黑色。通过GetScalarPointer(i,j,k)函数获取访问图像像素值。需要注意的是,GetScalarPointer()函数返回的是void*类型,因此需要根据图像的实际类型进行强制转换。示例中将像素数组的头指针类型转换为unsigned char*。
  此外,需要注意的地方:VTK彩色以及矢量图像采用的是如下图所示的像素存储格式:
  
这里写图片描述

  因此在修改RGB图像以及矢量图像像素时,需要根据像素的元组的组分数目来访问。示例中先获得第(i,j,k)个像素的地址也就是R值的地址,然后将地址加1来访问后续G值和B值。如果对像素的元组组分不确定,可以通过函数GetNumberOfScalarComponent()获取,代码如下:

int nbOfComp = reader->GetOutput->GetNumberOfScalarComponent()

二、迭代器访问

  第二种方法是用vtkImageIterator类实现迭代器方法访问图像像素。该类是一个模板类,使用时,需要提供迭代的图像像素类型以及迭代的区域大小。

示例演示

CMakeLists.txt代码

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(VisitImagePixelIterativelyExample)
FIND_PACKAGE(VTK REQUIRED)
INCLUDE(${VTK_USE_FILE})
ADD_EXECUTABLE(VisitImagePixelIterativelyExampleVisitImagePixelIterativelyExample.cpp)
TARGET_LINK_LIBRARIES(VisitImagePixelIterativelyExample ${VTK_LIBRARIES})

VisitImagePixelIterativelyExample.cpp文件代码如下:

/**********************************************************************

文件名: VisitImagePixelIterativelyExample.cpp
Copyright (c) 阿Bin先生. All rights reserved.
更多信息请访问: http://blog.csdn.net/webzhuce

**********************************************************************/

#include <vtkSmartPointer.h>
#include <vtkImageViewer2.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkBMPReader.h>
#include <vtkImageData.h>
#include <vtkImageIterator.h>


int main(int argc, char* argv[])
{
    vtkSmartPointer<vtkBMPReader> reader =
        vtkSmartPointer<vtkBMPReader>::New();
    //测试图像:E:\\TestData\\masonry.bmp
    reader->SetFileName ( "E:\\TestData\\masonry.bmp" );
    reader->Update();

    int subRegion[6] = {0,100, 0, 100, 0, 0};
    vtkImageIterator<unsigned char> it(reader->GetOutput(), subRegion);

    while(!it.IsAtEnd())
    {
        unsigned char *inSI = it.BeginSpan();
        unsigned char *inSIEnd = it.EndSpan();

        while(inSI != inSIEnd)
        {
            *inSI = 255-*inSI;
            ++inSI;
        }
        it.NextSpan();
    }

    vtkSmartPointer<vtkImageViewer2> imageViewer =
        vtkSmartPointer<vtkImageViewer2>::New();
    imageViewer->SetInputConnection(reader->GetOutputPort());

    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
    imageViewer->SetupInteractor(renderWindowInteractor);
    imageViewer->Render();
    imageViewer->GetRenderer()->ResetCamera();
    imageViewer->Render();

    imageViewer->GetRenderer()->SetBackground(1.0, 1.0, 1.0);
    imageViewer->SetSize(640, 480);
    imageViewer->GetRenderWindow()->SetWindowName("VisitImagePixelIterativelyExample");

    renderWindowInteractor->Start();

    return EXIT_SUCCESS;
}

运行结果:

这里写图片描述

   示例读取了一幅BMP图像,然后定义一个子区域。注意:在定义子区域时,不要超过图像的大小范围。然后根据图像类型unsigned char定义一个图像迭代器it,定义it时有两个参数:一个是要访问的图像,另一个是访问的图像区域。设置完毕,迭代器开始工作第一个while循环是判断迭代器是否结束。进入循环后,对于每一个迭代器it,又存在第二个循环,判断的是当前像素的元组(Tuple)是否迭代完毕。由于VTK中所有类型的图像格式都是vtkImageData,因此每个像素可能是标量,也可能是矢量。因此,每当访问到一个像素时需要迭代当前像素的元组。元组迭代时,inSI = it.BeginSpan()获取第一个组分,inEnd = it.EndSpan()表示组分迭代完毕。

2018-08-04 07:17:50 weixin_33935505 阅读数 35

图像的深度和通道

图像的深度

图像中像素点占得bit位数,就是图像的深度,比如以下图像的深度。

二值图像:

图像的像素点不是0 就是1 (图像不是黑色就是白色),图像像素点占的位数就是 1 位,图像的深度就是1,也称作位图。

灰度图像:

图像的像素点位于0-255之间,(0:全黑,255代表:全白,在0-255之间插入了255个等级的灰度)。最大值255的二进制表示为11111111,占有8个bit位,即2^8=256,图像的深度是8。

图像的通道

通道,是数字图像中存储不同类型信息的灰度图像。一个图像最多可以有数十个通道,常用的RGB和Lab图像默认有三个通道,而CMYK图像则默认有四个通道。 一张RGB图像含有三个通道:红(Red)、绿(Green)、蓝(Blue)。 一张CMYK图像含有四个通道:青色(Cyan)、品红(Magenta)、黄色、黑色。

所以想灰度图就只有一个通道,占有8个bit位,也就是8位图。所以RGB图像占有三个通道,3*8=24,所以RGB图像就是24位图。

图像在内存中的存储

图像像素点的存储就是对应的原图从左到右,从上到下,依次排列,每个点的值就是就是像素点的值,每个点的地址就是像素像素点的地址。

如第一幅图就是灰度图的存储,只有单通道。在内存中的存储即可用一个一维数组来表示,根据顺序从左到右,从上到下,依次按顺序存入数组。

图二则为RGB图像的存储模型,每一个像素有3个通道,所以需要一个二维数组来表示,顺序也是从左到右,从上到下,如[[234,200,0],[234,0,0],[255,55,0],....]这样,当然其中的数子,在内存中需要用对应的二进制来表示。

python输出图像数据

我们来用python来输出一个图片的像素数据,来验证看看上面所说的存储模型。

import sys
import tensorflow as tf
from PIL import Image, ImageFilter
import numpy as np

def imageprepare(argv):
    testImage=Image.open(argv).convert('L')
    testImage = testImage.resize((6, 4))
    test_input=np.array(testImage)
    print(test_input)


def main(argv):
    """
    Main function.
    """
    imvalue = imageprepare(argv)
    
if __name__ == "__main__":
    main(sys.argv[1])
复制代码

我这里传进去一张图片,然后转换成L模型(L表示灰度图),设置宽高位(6,4),输出如下所示,这里np.array把图片数据转换成了一个二维数组,方便根据(x,y)来读取:

[[254 255 254  97 255 248]
 [246 255  15 180 255 255]
 [252 227 227 246  44 252]
 [244 254 229 151 243 248]]
复制代码

如我们之前所说根据从左到右,从上到下存储的话,则可以方便的用以下方法来读取:

width = testImage.size[0]
height = testImage.size[1]
y = 0
while y<height:
    x = 0
    while x<width:
        print(test_input[y,x])
        x += 1
    y += 1
复制代码

对应的RGB图片,我们转换模型改一下testImage=Image.open(argv).convert('RGB'),转换为array之后,就变成了一个rowscolschannels的三维矩阵,输出读取如下所示:

[[[254 254 254]
  [255 255 255]
  [254 254 254]
  [ 97  97  97]
  [255 255 255]
  [248 248 248]]

 [[246 246 246]
  [255 255 255]
  [ 15  15  15]
  [180 180 180]
  [255 255 255]
  [255 255 255]]

 [[252 252 252]
  [227 227 227]
  [227 227 227]
  [246 246 246]
  [ 44  44  44]
  [252 252 252]]

 [[244 244 244]
  [254 254 254]
  [229 229 229]
  [151 151 151]
  [243 243 243]
  [248 248 248]]]
复制代码
width = testImage.size[0]
height = testImage.size[1]
y = 0
while y<height:
    x = 0
    while x<width:
        # 像素的3通道值
        print(test_input[y,x])
        print('R: ' + str(test_input[y,x,0]))
        print('G: ' + str(test_input[y,x,1]))
        print('B: ' + str(test_input[y,x,2]))
        x += 1
    y += 1
复制代码

iOS仿python图像处理库PIL

python代码

以下为python中PIL把图片转换为像素数据数组的代码,我们先把图片转化为RGBA格式,然后输出对应位置的像素数据。当然RGBA一个像素有4个通道,所以我们可以依次输出每个通道的值,如R通道:test_input[y,x,0]

def imageprepare(argv):
    testImage=Image.open(argv).convert('RGBA')
    testImage = testImage.resize((28, 28))
    test_input=np.array(testImage)
    print(test_input)
    width = testImage.size[0]
    height = testImage.size[1]
    y = 0
    while y<height:
        x = 0
        while x<width:
            print(test_input[y,x])
            # print('R: ' + str(test_input[y,x,0]))
            x += 1
        y += 1
复制代码

iOS代码

在iOS中图片转化为图片数据格式相对于python和Android中来讲相对麻烦一些,所以我这里封装了一个iOS图片转图片数据的类。输出的格式跟python中类似,但是python支持多种编码格式,分别为1,L,P,RGB,RGBA,CMYK,YCbCr,I,F。这里iOS开发中只支持RGBA,CMYK。

在iOS中我们会先根据图片的编码格式来生成一个CGContextRef(画布),以下代码是对RGBA格式图片处理生成的CGContextRef。

- (CGContextRef) newBitmapRGBA8ContextFromImage:(CGImageRef) image {
    
    CGContextRef context = NULL;
    CGColorSpaceRef colorSpace;
    uint32_t *bitmapData;
    
    size_t bitsPerPixel = 32;
    size_t bitsPerComponent = 8;
    size_t bytesPerPixel = bitsPerPixel / bitsPerComponent;
    
    size_t width = CGImageGetWidth(image);
    size_t height = CGImageGetHeight(image);
    
    size_t bytesPerRow = width * bytesPerPixel;
    size_t bufferLength = bytesPerRow * height;
    
    colorSpace = CGColorSpaceCreateDeviceRGB();
    
    if(!colorSpace) {
        NSLog(@"Error allocating color space Gray\n");
        return NULL;
    }
    
    // Allocate memory for image data
    bitmapData = (uint32_t *)malloc(bufferLength);
    
    if(!bitmapData) {
        NSLog(@"Error allocating memory for bitmap\n");
        CGColorSpaceRelease(colorSpace);
        return NULL;
    }
    
    //Create bitmap context
    
    context = CGBitmapContextCreate(bitmapData,
                                    width,
                                    height,
                                    bitsPerComponent,
                                    bytesPerRow,
                                    colorSpace,
                                    kCGImageAlphaPremultipliedLast); 
    if(!context) {
        free(bitmapData);
        NSLog(@"Bitmap context not created");
    }
    
    CGColorSpaceRelease(colorSpace);
    
    return context;
}
复制代码

要理解以上代码,首先要知道什么是像素格式:

位图其实就是一个像素数组,而像素格式则是用来描述每个像素的组成格式,它包括以下信息:

Bits per component :一个像素中每个独立的颜色分量使用的 bit 数;
Bits per pixel : 一个像素使用的总 bit 数;
Bytes per row : 位图中的每一行使用的字节数。

有一点需要注意的是,对于位图来说,像素格式并不是随意组合的,目前iOS、Mac OS X开发只支持以下有限的 17 种特定组合: 官方文档

源码

DSImageBitmaps这是我iOS源码的地址,其中包含了python的代码,我iOS里面的图片直接使用的是python裁剪过大小的图片,然后能发现数据的数据是一样的。

但是我用iOS里面直接裁剪大小后的图片就跟python处理过大小的图片输出的数据就不一样了,说是python的image.resize用到了滤波器,具体是什么我也不太清楚。反正就是iOS和python处理图片大小内部的算法有些许差异,但是你能发现每一个像素上的数据差异不大,具体到一张图显示的话人眼是识别不出来的。

还有就算要注意iOS中处理的图片大小问题,也就是iOS中像素和image.size的关系:

test.png (像素 20*20) test@2x.png(像素40*40) test@3x.png(像素 60*60)

UIImage *image = [UIImageimageNamed:@"test.png"];

image.size输出大小为(20,20);


UIImage *image = [UIImage imageNamed:@"test@2x.png"];

image.size输出大小为(20,20);


UIImage *image = [UIImage imageNamed:@"test@3x.png"];

image.size输出大小为(20,20);


image.size输出的大小会自动识别图片是几倍的,如果是3倍的输出的结果就是像素除以3,2倍的像素除以2。
复制代码

参考

Converting UIImage to RGBA8 Bitmaps and Back

一张图片引发的深思

谈谈 iOS 中图片的解压缩

2019-04-25 21:12:52 zaishuiyifangxym 阅读数 723

目录

1 传统方法读取与修改图像的像素值

1.1 读取图像的像素值

1.2 修改图像的像素值

2 使用Numpy库读取像素方法与修改图像的像素值

2.1 读取图像的像素值

2.2 修改图像的像素值

参考资料


1 传统方法读取与修改图像的像素值

1.1 读取图像的像素值

(1)读取灰度图像

例如:
img = cv2.imread("lena1.tiff", cv2.IMREAD_UNCHANGED) #读取图片
p = img[100, 200]  #获取图像的灰度值
print(p)                   #打印图像的灰度值

代码如下所示:

# -*- coding:utf-8 -*-
import cv2

#读取图片
img = cv2.imread("lena1.tiff", cv2.IMREAD_UNCHANGED)

#灰度图像
p = img[100, 200]
print(p)

#显示图像
cv2.imshow("Demo", img)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

 

结果如下图所示:

 

(2)读取RGB图像

# 方法1
b = img[100, 200, 0] # 注意和Matlab的区别
print(b)
g = img[100, 200, 1]
print(g)
r = img[100, 200, 2]
print(r)

# 方法2
bgr = img[100, 200]
print(bgr)

代码如下所示:

# -*- coding:utf-8 -*-
import cv2

#读取图片
img = cv2.imread("lena.tiff", cv2.IMREAD_UNCHANGED)

#BGR图像
#方法1
b = img[100, 200, 0]
print(b)
g = img[100, 200, 1]
print(g)
r = img[100, 200, 2]
print(r)

print('---------------')
#方法2
bgr = img[100, 200]
print(bgr)

#显示图像
cv2.imshow("Demo", img)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

 

运行结果如下图所示:

 

 

1.2 修改图像的像素值

(1)修改单个像素点的像素值

RGB图像可以通过位置参数直接访问像素值并进行修改.

代码如下所示:

# -*- coding:utf-8 -*-
import cv2

#读取图片
img = cv2.imread("lena.tiff", cv2.IMREAD_UNCHANGED)

#BGR图像
#方法1
b = img[100, 200, 0]
print(b)
g = img[100, 200, 1]
print(g)
r = img[100, 200, 2]
print(r)

print('---------------')
img[100, 200, 0]=255
img[100, 200, 1]=255
img[100, 200, 2]=255
b1 = img[100, 200, 0]
print(b1)
g1 = img[100, 200, 1]
print(g1)
r1 = img[100, 200, 2]
print(r1)
print('---------------')
# #方法2
print(img[100, 200])
print('---------------')
img[100, 200] = [10, 10, 10]
print(img[100, 200])

 

运行结果如下图所示:

 

(2)修改图像区域像素的像素值

通过访问图像数组的位置区域实现区域像素修改;

例如: [100:200,300:400] 是访问第100到200行,300到400列的区域,再对该区域像素进行修改

代码如下所示:

# -*- coding:utf-8 -*-
import cv2

#读取图片
img = cv2.imread("lena.tiff", cv2.IMREAD_UNCHANGED)

#BGR图像
img[100:200, 300:400] = [255, 255, 255] #修改图像像素区域的像素值 
                                        #修改第100到200行,300到400列的区域

#显示图像
cv2.imshow("Demo", img)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

运行结果如下图所示:


 

2 使用Numpy库读取像素方法与修改图像的像素值

2.1 读取图像的像素值

使用Numpy的 item 函数进行像素读取,调用方式如下:

返回值 = 图像.item(位置参数)

例如:(注意需要 导入numpy

# Numpy读取像素
blue = img.item(100, 200, 0)
green = img.item(100, 200, 1)
red = img.item(100, 200, 2)

代码如下所示:

# -*- coding:utf-8 -*-
import cv2
import numpy

#读取图片
img = cv2.imread("lena.tiff", cv2.IMREAD_UNCHANGED)

# Numpy读取像素
blue = img.item(100, 200, 0)
green = img.item(100, 200, 1)
red = img.item(100, 200, 2)
print(blue)
print(green)
print(red)

#显示图像
cv2.imshow("Demo", img)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

 

运行结果如下图所示:

注:OpenCV读取图像通道是BGR,也可以转换成RGB在进行处理。
 

 

2.2 修改图像的像素值

使用Numpy的 itemset 函数修改像素,调用方式如下:

图像.itemset(位置, 新值)

例如:

img.itemset((100, 200, 0), 255)

代码如下所示:

# -*- coding:utf-8 -*-
import cv2
import numpy

#读取图片
img = cv2.imread("lena.tiff", cv2.IMREAD_UNCHANGED)

#Numpy读取像素
print(img.item(100, 200, 0))
print(img.item(100, 200, 1))
print(img.item(100, 200, 2))

print('--------')
#Numpy 修改像素
img.itemset((100, 200, 0), 255)
img.itemset((100, 200, 1), 255)
img.itemset((100, 200, 2), 255)

#Numpy读取像素
print(img.item(100, 200, 0))
print(img.item(100, 200, 1))
print(img.item(100, 200, 2))

运行结果如下图所示:


 

参考资料

[1] https://blog.csdn.net/eastmount/article/details/82120114

[2] Python+OpenCV图像处理

没有更多推荐了,返回首页