硬解jpeg的exif信息

关于图片文件旋转JPEG与EXIF信息 关于图片文件旋转JPEG与EXIF信息 比如某相机拍摄出来的相片,文件分辨率比如宽度7360像素,高度4912像素 十进制表示为 DEC : 7360 * 4912 十六进制则为 HEX : 1CC0 * 1330 默认情况下,会在00000030:07标志位(不同设备或程序生成的图片的标志位会有所不同,由EXIF内容而定)上存放01值表示原始文件的位置,无论这张图是横着拍的还是坚着拍的,初... 阅读详情
AI摘要

本文探讨了使用C++标准库直接读取JPEG图像的Exif信息,介绍了Exif数据结构,如IFD(ImageFileDirectory)和XMP元数据,以及如何通过解析APP0和APP1区域来提取Exif数据,包括相机制造商、分辨率等信息。

当前有很多库能硬解jpeg图像信息,但如果是硬解呢,不依赖其他图形库,只通过c++标准库进行读取可行吗。

jpeg的结构

首先,我们可以参考Description of Exif file format这篇文章和JPG这篇文章,可以看出jpeg的结构基本如下:
jpeg文件结构
另一份exif的数据详细解析
Exif值解析
从这份表单可以看出,这个图片的exif信息还是很多的。但是!当我使用代码强行提取的时候,发现提取到的exif信息远小于表单上的数据!这是因为一部分图片拥有的exif信息是不完全的。

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <sstream>
#include <string>

struct ExifData {
    std::string cameraModel;
    std::string creationDate;
    int rating;
    std::string description;
    int xResolution;
    int yResolution;
    int resolutionUnit; // 1 = no-unit, 2 = inch, 3 = cm
};



// 查找和提取 Exif 数据
std::string findAndExtractExifData(const std::vector<unsigned char>& imageData) {
    // 查找 Exif 数据的开始
    std::vector<unsigned char> startMarker(2) ;
     startMarker[0] = 0xFF;
     startMarker[1] = 0xE1;
    auto startIter = std::search(imageData.begin(), imageData.end(), startMarker.begin(), startMarker.end());
    if (startIter == imageData.end()) {
        std::cout << "未找到 Exif 数据的开始" << std::endl;
        return "";
    }

    // 获取 Exif 数据的长度
    auto exifLengthIter = startIter + 2;
    unsigned short exifLength = (static_cast<unsigned short>(*(exifLengthIter)) << 8) | static_cast<unsigned short>(*(exifLengthIter + 1));
    std::cout << "Exif 数据长度: " << exifLength << std::endl;

    // 提取 Exif 数据
    std::vector<unsigned char> exifData(exifLength);
    std::copy(startIter, startIter + exifLength, exifData.begin());

    // 返回 Exif 数据的字符串形式
    return std::string(reinterpret_cast<char*>(exifData.data()), exifData.size());
}

int main() {
    // 从 JPEG 图像文件中读取数据
    std::ifstream file("your_image_path/image.jpg", std::ios::binary | std::ios::ate);
    if (!file.is_open()) {
        std::cerr << "无法打开图像文件" << std::endl;
        return 1;
    }

    std::streamsize fileSize = file.tellg();
    file.seekg(0, std::ios::beg);

    std::vector<unsigned char> imageData(fileSize);
    if (!file.read(reinterpret_cast<char*>(imageData.data()), fileSize)) {
        std::cerr << "无法读取图像文件" << std::endl;
        return 1;
    }

    // 查找并提取 Exif 数据
    std::string exifData = findAndExtractExifData(imageData);

    // 输出 Exif 数据
    std::cout << exifData << std::endl;

    return 0;
}

输出的值如下

Exif 数据长度: 2905
��
Yhttp://ns.adobe.com/xap/1.0/<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x=“adobe:ns:meta/” x:xmptk=“XMP Core 6.0.0”>
<rdf:RDF xmlns:rdf=“http://www.w3.org/1999/02/22-rdf-syntax-ns#”>
<rdf:Description rdf:about=“”
xmlns:xmp=“http://ns.adobe.com/xap/1.0/”
xmlns:dc=“http://purl.org/dc/elements/1.1/”
xmlns:tiff=“http://ns.adobe.com/tiff/1.0/”>
xmp:CreatorToolNIKON D810 Ver.1.01 </xmp:CreatorTool>
xmp:CreateDate2018:11:20 10:40:31</xmp:CreateDate>
xmp:Rating0</xmp:Rating>
tiff:XResolution300</tiff:XResolution>
tiff:YResolution300</tiff:YResolution>
tiff:ResolutionUnit2</tiff:ResolutionUnit>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta> <?xpacket end="w

其中能读出的数据有:

根节点是 <x:xmpmeta>, 其中包含了 3 个命名空间:
xmlns:x=“adobe:ns:meta/”: Adobe 自定义的 XMP 元数据命名空间
xmlns:rdf=“http://www.w3.org/1999/02/22-rdf-syntax-ns#”: RDF (Resource Description Framework) 语法命名空间
xmlns:xmp=“http://ns.adobe.com/xap/1.0/”: XMP 核心属性命名空间
xmlns:dc=“http://purl.org/dc/elements/1.1/”: Dublin Core 元数据属性命名空间
xmlns:tiff=“http://ns.adobe.com/tiff/1.0/”: TIFF 图像元数据属性命名空间

在 rdf:Description 节点中,我们可以获取到:
xmp:CreatorTool: 创建该图像的工具,是 “NIKON D810 Ver.1.01”
xmp:CreateDate: 图像的创建日期,是 “2018:11:20 10:40:31”
xmp:Rating: 图像的评分,是 “0”
tiff:XResolution: 图像的水平分辨率,是 “300”
tiff:YResolution: 图像的垂直分辨率,是 “300”
tiff:ResolutionUnit: 分辨率的单位,是 “2” (代表英寸)

这个时候,细心的朋友可能发现了,我们的有效信息一般是由 <?xpacket begin= 开始而由 <?xpacket end= 结束(事实上在结束标志前还有一大片空数据)因此实际结束位应该是一定数量的空数据或者 <?xpacket end= 知道这个信息就好办了,我们就可以用一个函数来硬解图片exif数据

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <unordered_map>

std::string extractExifData(const std::string& filename) {
    std::ifstream file(filename, std::ios::binary);

    if (!file) {
        std::cout << "无法打开文件: " << filename << std::endl;
        return "";
    }

    std::vector<char> imageData((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
    file.close();

    std::string exifData;
    std::string startMarker = "<?xpacket begin=";
    std::string endMarker = "    ";

    size_t startPos = std::string(imageData.begin(), imageData.end()).find(startMarker);
    if (startPos != std::string::npos) {
        size_t endPos = std::string(imageData.begin() + startPos, imageData.end()).find(endMarker);
        if (endPos != std::string::npos) {
            endPos += startPos;
            exifData = std::string(imageData.begin() + startPos, imageData.begin() + endPos + endMarker.length() + 3);
        }
    }

    return exifData;
}

此时我们能获取到各种类型图片的内嵌xmp信息,其中就有我们需要的部分信息,只要对其中数据进行提取就可以获得数据
在这里插入图片描述

读取的值其实还不是exif图,而是内嵌的xmp文件,为妾这样读取效率太慢,这个时候,我们就可以思考有没有更佳优异的读取exif信息的方式了。
这个时候我们就要理解一个概念叫IFD,这个数据结构长12位由2位tag,2位type,4位count和4位offset组成,其中,tag是标签名,每个tag(2位16进制数)都会对应一个标签,比如0x010f就是make标签,代表相机制造商信息,具体的标签名对应列表参考这个文档Exif2.3标签名。

此时我们就可以正确读取了,以EXIF格式的jpeg为例,首先我们读取前两位是否为0xFF 0xD8,然后读取四位看是0xE0还是0xE1,如果是0xE0则是APP0区域,位JFIF空间,如果是0xE1则是APP1区域为Exif空间
Exif和Jfif对比
因此,如果是JFIF,提取数据就比较简单了,不需要考虑大小端啥的,按照维基百科-JPEG文件交换格式

JFIF文件结构如下
JFIF文件结构
APP0标记段如下
APP0
单纯读取JFIF信息就可以只读EXIF空格后的几位
而读取EXIF数据则复杂得多。
首先,用文件指针读取第一二位,确定是否为FFD8,如果是则下一步,否输出不是jpeg文件,然后读取第三四位看是FFE0还是FFE1,如果是FFE0则为JFIF格式,如果为FFE1则为EXIF格式,如果是EXIF存储格式,则读取第13和14位,看是否为II或者MM如果是II则为小端存储,MM则为大端存储,然后读取其21位和22位(此时开始读取需要遵守之前读取的大小端规则)确定总体tag数量比如刚刚读取到II,现在读取到0D00则有13个tag然后开始将数据写入IFD中。
进行完逻辑之后,我们就读取到了第一个非常有用的数据IFD( Image File Directory),然后再针对性进行解码,下面是一个示例

#include <i386/endian.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <string>

using namespace std;


// 字节序枚举
enum ByteOrder {
    LITTLE,
    BIG
};

enum DataType {
    Byte = 1,
    Ascii = 2,
    Short = 3,
    Long = 4,
    Rational = 5,
    Undefined = 7,
    SignedRational = 10,
    Float = 11,
    Double = 12
};

// IFD结构体
struct IFD {
    unsigned short tagName;
    unsigned short type;
    unsigned int count;
    unsigned int offset;
};

// 读取2个字节
unsigned short readShort(ifstream& file, ByteOrder byteOrder) {
    unsigned char bytes[2];
    file.read(reinterpret_cast<char*>(bytes), 2);
    if (byteOrder == LITTLE) {
        return (bytes[1] << 8) + bytes[0];
    } else {
        return (bytes[0] << 8) + bytes[1];
    }
}

// 读取4个字节
unsigned int readLong(ifstream& file, ByteOrder byteOrder) {
    unsigned char bytes[4];
    file.read(reinterpret_cast<char*>(bytes), 4);
    if (byteOrder == LITTLE) {
        return (bytes[3] << 24) + (bytes[2] << 16) + (bytes[1] << 8) + bytes[0];
    } else {
        return (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3];
    }
}

// 解析IFD结构体中的标记名称和标记值
void parseIFDValue(ifstream& file, ByteOrder byteOrder, const IFD& ifd, const map<unsigned short, string>& tagNames) {
    // 输出标记名称
    if (tagNames.find(ifd.tagName) != tagNames.end()) {
        cout << "标记名称: " << tagNames.at(ifd.tagName);
    } else {
        cout << "未知标记: 0x" << hex << ifd.tagName;
    }

    // 根据类型解析标记值
    switch (ifd.type) {
            case Ascii: {
            streampos currentPos = file.tellg();
            file.seekg(ifd.offset, ios::beg);
            vector<char> buffer(ifd.count);
            file.read(buffer.data(), ifd.count);
            string value(buffer.begin(), buffer.end());
            cout << " 标记值: " << value << endl;
            file.seekg(currentPos);
        }
        break;
        case Short: {
            if (ifd.count == 1) {
                cout << " 标记值: " << ifd.offset << endl;
            } else {
                streampos currentPos = file.tellg();
                cout << " 标记值 ";
                file.seekg(ifd.offset, ios::beg);
                for (unsigned int i = 0; i < ifd.count; i++) {
                    unsigned short value = readShort(file, byteOrder);
                    cout<< value << endl;
                }
                cout << endl;
                file.seekg(currentPos);
            }
        }
        break;
        case Long: {
            if (ifd.count == 1) {
                cout << " 标记值: " << ifd.offset << endl;
            } else {
                streampos currentPos = file.tellg();
                file.seekg(ifd.offset, ios::beg);
                cout << " 标记值 ";
                for (unsigned int i = 0; i < ifd.count; i++) {
                    unsigned int value = readLong(file, byteOrder);
                    cout <<  value ;
                }
                cout << endl;
                file.seekg(currentPos);
            }
        }
        break;
        // 其他类型的处理...
        default:
            cout << "未处理的数据类型: " << ifd.type << endl;
            break;
    }
    cout << endl;
}

// 解析EXIF元数据
void parseExif(const string& filename) {
    ifstream file(filename, ios::binary);
    if (!file) {
        cout << "无法打开文件: " << filename << endl;
        return;
    }

    // 读取前两个字节,确定是否为JPEG文件
    unsigned short marker = readShort(file, BIG);
    if (marker != 0xFFD8) {
        cout << "不是JPEG文件" << endl;
        return;
    }

    // 读取下一个标记
    marker = readShort(file, BIG);
    if (marker != 0xFFE0 && marker != 0xFFE1) {
        cout << "不是JFIF或EXIF格式" << endl;
        return;
    }

    // 如果是EXIF格式,读取字节序和标记数量
    ByteOrder byteOrder;
    unsigned int ifdOffset = 0;
    if (marker == 0xFFE1) {
        file.seekg(8, ios::cur); // 跳过EXIF头
        unsigned short byteOrderMarker = readShort(file, BIG);
        cout << "字节序: " << byteOrderMarker << endl;
        if (byteOrderMarker == 0x4949) {
            byteOrder = LITTLE;
        } else if (byteOrderMarker == 0x4D4D) {
            byteOrder = BIG;
        } else {
            cout << "无效的字节序" << endl;
            return;
        }
        file.seekg(2, ios::cur); // 跳过42
        ifdOffset = readLong(file, byteOrder) + 12;
    }

    // 读取IFD
    file.seekg(ifdOffset, ios::beg);
    unsigned short tagCount = readShort(file, byteOrder);
    cout << "标记数量: " << tagCount << endl;

    // 定义标记名称映射
    map<unsigned short, string> tagNames;
    tagNames[0x010E] = "ImageDescription";
    tagNames[0x013B] = "Artist";
    tagNames[0x010F] = "Make";
    tagNames[0x0110] = "Model";
    tagNames[0x0112] = "Orientation";
    tagNames[0x011A] = "XResolution";
    tagNames[0x011B] = "YResolution";
    tagNames[0x0128] = "ResolutionUnit";
    tagNames[0x0131] = "Software";
    tagNames[0x0132] = "DateTime";
    tagNames[0x0213] = "YCbCrPositioning";
    tagNames[0x8769] = "ExifOffset";
    tagNames[0x8298] = "Copyright";
    tagNames[0x829A] = "ExposureTime";
    tagNames[0x829D] = "FNumber";
    tagNames[0x8822] = "ExposureProgram";
    tagNames[0x8825] = "GPSInfo";
    tagNames[0x8827] = "ISOSpeedRatings";
    tagNames[0x9000] = "ExifVersion";
    tagNames[0x9003] = "DateTimeOriginal";
    tagNames[0x9004] = "DateTimeDigitized";
    tagNames[0x9204] = "ExposureBiasValue";
    tagNames[0x9205] = "MaxApertureValue";
    tagNames[0x9207] = "MeteringMode";
    tagNames[0x9208] = "Lightsource";
    tagNames[0x9209] = "Flash";
    tagNames[0x920A] = "FocalLength";
    tagNames[0x927C] = "MakerNote";
    tagNames[0x9286] = "UserComment";
    tagNames[0xA000] = "FlashPixVersion";
    tagNames[0xA001] = "ColorSpace";
    tagNames[0xA002] = "ExifImageWidth";
    tagNames[0xA003] = "ExifImageLength";
    tagNames[0xA433] = "LensMake";
    tagNames[0xA434] = "LensModel";
    
    vector<IFD> ifds(tagCount);
    // 读取IFD结构体
    for (int i = 0; i < tagCount; i++) {
        ifds[i].tagName = readShort(file, byteOrder);
        ifds[i].type = readShort(file, byteOrder);
        ifds[i].count = readLong(file, byteOrder);
        ifds[i].offset = readLong(file, byteOrder) + 12;

        // // 输出IFD信息
        // if (tagNames.find(ifds[i].tagName) != tagNames.end()) {
        //     cout << "标记名称: " << tagNames[ifds[i].tagName];
        // } else {
        //     cout << "未知标记: 0x" << hex << ifds[i].tagName;
        // }
        // cout << " 类型: " << ifds[i].type ;
        // cout << " 数量: " << ifds[i].count;
        // cout << " 偏移量: " << ifds[i].offset << endl;
        // cout << endl;
        parseIFDValue(file, byteOrder, ifds[i], tagNames);
    }

    file.close();
}

解析完成就可以拿到exif数据啦
在这里插入图片描述

等等,这样我们只解析了一个区块的exif信息,要完整解析还得再获取一个偏移量获得下一区块的位置,而且如果偏移量少于tagcout*12的情况,原偏移量所在位置就是值位置,也就是说,如果偏移量为1,那么值就为1

使用libexif开源库修改jpeg相片exif信息 libexif简介 libexif是一个开源的图片exif信息操作库,提供了对exif信息常见操作接口; exif则是相片中的附属信息,常见的exif信息如图: 阅读详情

相关推荐

JPG图片叠加exif信息

<br />常见的图片格式有:<br />1、BMP格式 <br />Windows中的一各标准格式,用于存储独立于设备和应用程序的图象!所以一般的程序都很容易就可以读取BMP的图象!以象素为单位记录图片数据,每一象素可以有1、4、8、15、24、32和64位的颜色值!在文件头就给定了这些信息。24位的图片为通用的BMP文件!<br /><br />2、联合图象专家组压缩方案(JPEG) <br />JPEG压缩方案在扫描图象等自然景色方面表现很出色!某些信息在压缩的时候就丢失了!但为些往往是我们人眼所无法

自由的小鱼 2075

图像JPEG&EXIF格式介绍(一)

1、Jpeg介绍 JPEG(Joint Photographic Experts Group)是JPEG标准的产物,该标准由国际标准化组织(ISO)制订,是面向连续色调静止图像的一种压缩标准。JPEG格式是最常用的图像文件格式,后缀名为.jpg或.jpeg。 jpeg标准是在1992年被创建 2、Jpeg格式介绍 ...

zhxx120的专栏 5930

20170227. EXIF信息的说明(opencv320 ApplyExifOrientation)

在opencv3.2.0中,对imread函数做了修改 Mat imread( const String& filename, int flags ) { /// create the basic container Mat img; /// load the data imread_( filename, flags, LOAD_MAT, &img );

u014488388的专栏 2550

XPath语言

XPath语言是一门专门用于在XML文档中查找信息的语言,其他XML程序可利用XPath在XML文档中对元素和属性进行导航 我们之所以需要这个导航是因为我们的XML文档是用来存储数据的,需要将数据提取出来使用,所以通过查找标签和属性进一步获取数据 XPath节点 XPath基本概念: 基本值(或原子值): 基本值专门用于表示简单的数据值,例如整数值、字符串。我们可以把...

成长日记的博客 709

西门子S7-200 SMART与施耐德ATV变频器Modbus通讯实战:从接线到稳定运行的完整指南

本文详细介绍了西门子S7-200 SMART PLC与施耐德ATV变频器之间实现稳定Modbus通讯的完整实战指南。内容涵盖从硬件接线、参数配置、PLC程序编写到触摸屏设计的全流程,并分享了提升通讯稳定性的关键技巧和常见故障排查方法,助力工业自动化系统可靠运行。

kkk56的博客 1108

告别龟速与断连:Arduino IDE下ESP32及ESP32-CAM一站式环境部署指南

本文提供Arduino IDE下ESP32及ESP32-CAM一站式环境部署指南,解决下载速度慢、断连等常见问题。通过国内镜像源加速、详细步骤讲解和ESP32-CAM专属配置技巧,帮助开发者快速完成环境搭建,避免常见陷阱,提升开发效率。

weixin_30576827的博客 771

jpeg图片的exif信息

EXIF(Exchangeable Image File)是“可交换图像文件”的缩写,当中包含了专门为数码相机的照片而定制的元数 据,可以记录数码照片的拍摄参数、缩略图及其他属性信息。exif其实是jpeg文件的一种,遵从jpeg标准,只是在文件 头信息中增加了有关拍摄信息的内容和索引图。 JEPG文件头必须以0xFF 0xD8开头,0xFF 0xD9结尾。然后后

sl8023dxf的专栏 3756

避坑指南:ZYNQ MPSOC QSPI固化时MT25QU256闪存的特殊配置

本文针对Xilinx ZYNQ UltraScale+ MPSoC平台,详细解析了使用Vitis工具将BOOT.bin固化至Micron MT25QU256ABA QSPI NOR Flash时的特殊配置与避坑指南。重点阐述了Init文件的真实作用、电压与频率的精确匹配策略,以及针对该闪存型号的初始化序列,帮助工程师解决烧录失败、启动异常等常见问题,确保系统可靠启动。

weixin_29175469的博客 271

C++ 获取整个文本内容

文件内容: <?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Descript...

老狼的专栏 1974

HMC7044调试指南与FPGA开发

最后,我们介绍了在FPGA开发中使用HMC7044的几个常见应用场景,包括时钟分配、时钟同步、高精度时钟生成和时钟域交叉。根据您的应用需求,您可以选择不同的时钟分配方案,例如使用PLL生成特定频率的时钟信号,或者通过分频器生成较低频率的时钟信号。HMC7044可以提供精确的时钟同步功能,确保各个FPGA板之间的时钟信号保持一致,从而实现可靠的数据传输和协同操作。HMC7044可以实现时钟域之间的交叉,通过生成和分配不同频率的时钟信号,使得不同时钟域的模块能够协同工作。FPGA开发中的HMC7044应用。

CqpFsharp的博客 3619

【Python进阶】VSCode Python开发完全指南:从环境配置到高效调试

本文通过15个实战案例,系统讲解VSCode进行Python开发的环境配置、编码技巧、调试方法及性能优化,帮助初学者快速构建专业开发环境。

赶紧的博客 3766

exif格式及解析库easyexif使用介绍

JPEG文件以字符串"0xFFD8"开头表示图像信息开始,以字符串"0xFFD9"结尾表示图像信息结束。在JPEG文件头中有一系列"0xFF??"格式的数据段,称为"标识",用来标记JPEG文件的信息段。0xFFEXIF 数据为照片管理和后期处理提供了丰富的元数据信息。摄影爱好者可以利用 EXIF 数据分类、排序、搜索照片,并根据拍摄参数优化后期编辑。总的来说, EXIF 格式为数码摄影带来了很大的便利。详细介绍exif的基本知识以及easexif库的使用。

yueguang8的博客 2285

【超详细】计算机组成原理总结及思维导图

计算机组成 第一章 计算机系统概论 冯诺依曼型计算机特点 1.计算机由运算器,控制器,存储器,输入和输出设备5部分组成 2.采用存储程序的方式,程序和数据放在同一个存储器中,并以二进制表示。 3.指令由操作码和地址码组成 4.指令在存储器中按执行顺序存放,由指令计数器(即程序计数器PC)指明要执行的指令所在的储存单元地址,一般按顺序递增,但可按运算结果或外界条件而改变 5.机器以运...

圣三一 10万+

JPEG文件中的EXIF(下)

元文链接 EXIF格式介绍(下) JPEG图片中的EXIF信息是以TIFF格式保存的,关于TIFF格式的介绍,可以参考上篇。 下篇中将介绍EXIF中都保存了哪些数据,这些数据的内容和格式,最后介绍一下EXIF中的缩略图信息。 JPEG图片的EXIF数据 EXIF JPEG文件将EXIF信息存储在JFIF的APP1标记中。

萌主不萌的专栏 2959

【用unity实现100个游戏之10】复刻经典俄罗斯方块游戏(附项目源码)

当今游戏产业中,经典游戏的复刻一直是一项受欢迎且具有挑战性的任务。俄罗斯方块是一个深入人心、令人上瘾的经典游戏,在过去几十年里一直享有广泛的流行度。其简单而富有策略性的玩法吸引了无数玩家的关注。因此,我决定利用Unity引擎来复刻这款经典游戏,以让更多的人重新体验其中的乐趣。通过使用Unity引擎,我能够利用其强大的工具和功能,从头开始构建一个与原版俄罗斯方块游戏相似的游戏。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 2797

【nnUNetv2进阶】四、nnUNetv2 魔改网络-小试牛刀-加入注意力机制ChannelAttention

本文介绍了在nnunet中加入ChannelAttention的方法,按照本文教的教程,可以快速完成ChannelAttention的加入和自定义模型的跑通。

AI爱好者的博客,分享计算机领域相关知识 5802

jpeg Exif file format  Marker APP1 简介

jpeg Exif file format Marker APP1 简介 jpeg Exif file format Marker APP1 分析 参考:Description of Exif file format Exif 文件格式与 JPEG 文件格式相同。 Exif 按照JPEG规范将图片的相关信息数据和缩略图图像插入JPEG。 因此可以使用Internet 浏览器/...

qq_38907791的博客 2146

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

EXIF信息及含义

说明: 文章内容属转载,0x的部分是代码,英文部分是EXIF规范名称,最后是数据类型。包括了数据计算说明以及某些项的数值含义,例如EXIF中色彩空间为short类型,其值是数字,代表含义为:1、黑白;2、RGB;6、YcbCr。 正文: JPEG格式和标志 JPEG文件都是以十六进制 '0xFFD8’开始,以’0xFFD9’结束。在JPEG数据中有像’0xFF**'这样的数据,这些被称为“标志”,它表示JPEG信息数据段。0xFFD8 表示SOI(Start of image 图像开始),0xFFD9表示E

Dunkle.T的博客 9193

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

JPEG系列二 JPEG文件中的EXIF(下)

https://blog.youkuaiyun.com/shelldon/article/details/54407534 EXIF格式介绍(下) JPEG图片中的EXIF信息是以TIFF格式保存的,关于TIFF格式的介绍,可以参考上篇。 下篇中将介绍EXIF中都保存了哪些数据,这些数据的内容和格式,最后介绍一下EXIF中的缩略图信息。 JPEG图片的EXIF数据 EXIF JPEG文件将EX...

子曰小玖的博客 1258

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

读取和修改JPEG图片文件的头信息EXIF和JFIF

本文链接:https://blog.youkuaiyun.com/xywy2008/article/details/38089789 1. JPEG图片格式的发展历程和简单介绍可参考下面的文章 http://en.wikipedia.org/wiki/JPEG http://blog.youkuaiyun.com/kickxxx/article/details/8173332 2. 读取JPEG图片文件头信息的工具 ...

xiatiancc的专栏 5803

获取JPEG文件中的EXIF信息旋转角度

【代码】获取JPEG文件中的EXIF信息旋转角度。

我的博客 946

JPEG Exif 学习

所有的JPEG文件以字符串“0xFFD8”开头,并以字符串“0xFFD9”结束。文件头中有一系列“0xFF??”格式的字符串,称为“标识”,用来标记JPEG文件的信息段。“0xFFD8”表示图像信息开始,“0xFFD9”表示图像信息结束,这两个标识后面没有信息,而其它标识紧跟一些信息字符。 0xFFE0 -- 0xFFEF之间的标识符称为“应用标记”,没有被常规JPEG文件利用,Exif正是

zcc1414的专栏 815

修改删除图片属性Exif信息的方法

首先下载jhead.exe文件,下载地址:http://www.sentex.net/~mwandel/jhead/jhead.exe 将下载下来的文件复制到Windows目录(这一点很重要,否则Windows会提示找不到文件)。  使用说明:  以下内容转自http://download.youkuaiyun.com/source/1791268 

zh_amin的专栏 2万+

Java 读取 JPEG 文件的 exif 信息

突然要用Java 读取 JPEG文件的信息, 宽度, 高度, 颜色表示等信息。 下载了一个工具jar 包 metadata-extractor-2.3.1.jar , 网上搜一下 放到lib 里面。 一个简单的类来读取信息 ReadFileProperties.java package com.founder.readfile; import java.io.File; import java.u

maxwellnewlife的专栏 740

jpeg exif_CompactExifLib:访问JPEG文件中的EXIF标签

Download ExifData1.1.zip - 17.9 KB 下载ExifData1.1.zip-17.9 KB 介绍 (Introduction) The EXIF standard is used by almost all photo and smartphone cameras for storing information about an image. The EXIF da...

cunhan4654的博客 724
上一篇: OpenGL实现全景图(SkyBox和Hdri双实现方式)
下一篇: 深入浅出的c++教程(基于C++Primer)第一章
可能是阿伦
博客等级 码龄7年 1424粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值