基于tensorflow的pix2pix代码中如何做到输入图像和输出图像分辨率不一致

问题:例如在自己制作了成对的输入(input256×256 target 200×256)后,如何让输入图像和输出图像分辨率不一致,例如成对图像中:input的分辨率是256×256, output 和target都是200×256,需要修改哪里的参数。

论文参考:《Image-to-Image Translation with Conditional Adversarial Networks》
代码参考:https://blog.csdn.net/MOU_IT/article/details/80802407?utm_source=blogxgwz0

coding=utf-8

from future import absolute_import
from future import division
from future import print_function

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import tensorflow as tf
import numpy as np
import os
import glob
import random
import collections
import math
import time

https://github.com/affinelayer/pix2pix-tensorflow

train_input_dir = "D:/Project/pix2pix-tensorflow-master/facades/train/" # 训练集输入
train_output_dir = "D:/Project/pix2pix-tensorflow-master/facades/train_out/" # 训练集输出

test_input_dir = "D:/Project/pix2pix-tensorflow-master/facades/val/" # 测试集输入
test_output_dir = "D:/Project/pix2pix-tensorflow-master/facades/test_out/" # 测试集的输出
checkpoint = "D:/Project/pix2pix-tensorflow-master/facades/train_out/" # 保存结果的目录

seed = None
max_steps = None # number of training steps (0 to disable)
max_epochs = 200 # number of training epochs

progress_freq = 50 # display progress every progress_freq steps
trace_freq = 0 # trace execution every trace_freq steps
display_freq = 50 # write current training images every display_freq steps
save_freq = 500 # save model every save_freq steps, 0 to disable

separable_conv = False # use separable convolutions in the generator
aspect_ratio = 1 #aspect ratio of output images (width/height)

batch_size = 1 # help="number of images in batch")
which_direction = "BtoA" # choices=["AtoB", "BtoA"])
ngf = 64 # help="number of generator filters in first conv layer")
ndf = 64 # help="number of discriminator filters in first conv layer")
scale_size = 286 # help="scale images to this size before cropping to 256x256")
flip = True # flip images horizontally
no_flip = True # don't flip images horizontally

lr = 0.0002 # initial learning rate for adam
beta1 = 0.5 # momentum term of adam
l1_weight = 100.0 # weight on L1 term for generator gradient
gan_weight = 1.0 # weight on GAN term for generator gradient

output_filetype = "png" # 输出图像的格式

EPS = 1e-12 # 极小数,防止梯度为损失为0
CROP_SIZE = 256 # 图片的裁剪大小

命名元组,用于存放加载的数据集合创建好的模型

Examples = collections.namedtuple("Examples", "paths, inputs, targets, count, steps_per_epoch")
Model = collections.namedtuple("Model",
"outputs, predict_real, predict_fake, discrim_loss, discrim_grads_and_vars, gen_loss_GAN, gen_loss_L1, gen_grads_and_vars, train")

图像预处理 [0, 1] => [-1, 1]

def preprocess(image):
with tf.name_scope("preprocess"):
return image * 2 - 1

图像后处理[-1, 1] => [0, 1]

def deprocess(image):
with tf.name_scope("deprocess"):
return (image + 1) / 2

判别器的卷积定义,batch_input为 [ batch , 256 , 256 , 6 ]

def discrim_conv(batch_input, out_channels, stride):
# [ batch , 256 , 256 , 6 ] ===>[ batch , 258 , 258 , 6 ]
padded_input = tf.pad(batch_input, [[0, 0], [1, 1], [1, 1], [0, 0]], mode="CONSTANT")
'''
[0,0]: 第一维batch大小不扩充
[1,1]:第二维图像宽度左右各扩充一列,用0填充
[1,1]:第三维图像高度上下各扩充一列,用0填充
[0,0]:第四维图像通道不做扩充
'''
return tf.layers.conv2d(padded_input, out_channels, kernel_size=4, strides=(stride, stride), padding="valid",
kernel_initializer=tf.random_normal_initializer(0, 0.02))

生成器的卷积定义,卷积核为4*4,步长为2,输出图像为输入的一半

def gen_conv(batch_input, out_channels):
# [batch, in_height, in_width, in_channels] => [batch, out_height, out_width, out_channels]
initializer = tf.random_normal_initializer(0, 0.02)
if separable_conv:
return tf.layers.separable_conv2d(batch_input, out_channels, kernel_size=4, strides=(2, 2), padding="same",
depthwise_initializer=initializer, pointwise_initializer=initializer)
else:
return tf.layers.conv2d(batch_input, out_channels, kernel_size=4, strides=(2, 2), padding="same",
kernel_initializer=initializer)

生成器的反卷积定义

def gen_deconv(batch_input, out_channels):
# [batch, in_height, in_width, in_channels] => [batch, out_height, out_width, out_channels]
initializer = tf.random_normal_initializer(0, 0.02)
if separable_conv:
_b, h, w, _c = batch_input.shape
resized_input = tf.image.resize_images(batch_input, [h * 2, w * 2],
method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)
return tf.layers.separable_conv2d(resized_input, out_channels, kernel_size=4, strides=(1, 1), padding="same",
depthwise_initializer=initializer, pointwise_initializer=initializer)
else:
return tf.layers.conv2d_transpose(batch_input, out_channels, kernel_size=4, strides=(2, 2), padding="same",
kernel_initializer=initializer)

定义LReLu激活函数

def lrelu(x, a):
with tf.name_scope("lrelu"):
# adding these together creates the leak part and linear part
# then cancels them out by subtracting/adding an absolute value term
# leak: a*x/2 - a*abs(x)/2
# linear: x/2 + abs(x)/2

    # this block looks like it has 2 inputs on the graph unless we do this
    x = tf.identity(x)
    return (0.5 * (1 + a)) * x + (0.5 * (1 - a)) * tf.abs(x)

批量归一化图像

def batchnorm(inputs):
return tf.layers.batch_normalization(inputs, axis=3, epsilon=1e-5, momentum=0.1, training=True,
gamma_initializer=tf.random_normal_initializer(1.0, 0.02))

检查图像的维度

def check_image(image):
assertion = tf.assert_equal(tf.shape(image)[-1], 3, message="image must have 3 color channels")
with tf.control_dependencies([assertion]):
image = tf.identity(image)

if image.get_shape().ndims not in (3, 4):
    raise ValueError("image must be either 3 or 4 dimensions")

# make the last dimension 3 so that you can unstack the colors
shape = list(image.get_shape())
shape[-1] = 3
image.set_shape(shape)
return image

去除文件的后缀,获取文件名

def get_name(path):
# os.path.basename(),返回path最后的文件名。若path以/或\结尾,那么就会返回空值。
# os.path.splitext(),分离文件名与扩展名;默认返回(fname,fextension)元组
name, _ = os.path.splitext(os.path.basename(path))
return name

加载数据集,从文件读取-->解码-->归一化--->拆分为输入和目标-->像素转为[-1,1]-->转变形状

def load_examples(input_dir):
if input_dir is None or not os.path.exists(input_dir):
raise Exception("input_dir does not exist")

# 匹配第一个参数的路径中所有的符合条件的文件,并将其以list的形式返回。
input_paths = glob.glob(os.path.join(input_dir, "*.jpg"))

# 图像解码器
decode = tf.image.decode_jpeg
if len(input_paths) == 0:
    input_paths = glob.glob(os.path.join(input_dir, "*.png"))
    decode = tf.image.decode_png

if len(input_paths) == 0:
    raise Exception("input_dir contains no image files")

# 如果文件名是数字,则用数字进行排序,否则用字母排序
if all(get_name(path).isdigit() for path in input_paths):
    input_paths = sorted(input_paths, key=lambda path: int(get_name(path)))
else:
    input_paths = sorted(input_paths)

sess = tf.Session()

with tf.name_scope("load_images"):
    # 把我们需要的全部文件打包为一个tf内部的queue类型,之后tf开文件就从这个queue中取目录了,
    # 如果是训练模式时,shuffle为True
    path_queue = tf.train.string_input_producer(input_paths, shuffle=True)

    # Read的输出将是一个文件名(key)和该文件的内容(value,每次读取一个文件,分多次读取)。
    reader = tf.WholeFileReader()
    paths, contents = reader.read(path_queue)

    # 对文件进行解码并且对图片作归一化处理
    raw_input = decode(contents)
    raw_input = tf.image.convert_image_dtype(raw_input, dtype=tf.float32)  # 归一化处理

    # 判断两个值知否相等,如果不等抛出异常
    assertion = tf.assert_equal(tf.shape(raw_input)[2], 3, message="image does not have 3 channels")
    '''
      对于control_dependencies这个管理器,只有当里面的操作是一个op时,才会生效,也就是先执行传入的
    参数op,再执行里面的op。如果里面的操作不是定义的op,图中就不会形成一个节点,这样该管理器就失效了。
    tf.identity是返回一个一模一样新的tensor的op,这会增加一个新节点到gragh中,这时control_dependencies就会生效.
    '''
    with tf.control_dependencies([assertion]):
        raw_input = tf.identity(raw_input)

    raw_input.set_shape([None, None, 3])

    # 图像值由[0,1]--->[-1, 1]
    width = tf.shape(raw_input)[1]  # [height, width, channels]
    a_images = preprocess(raw_input[:, :width // 2, :])  # 256*256*3
    b_images = preprocess(raw_input[:, width // 2:, :])  # 256*256*3

# 这里的which_direction为:BtoA
if which_direction == "AtoB":
    inputs, targets = [a_images, b_images]
elif which_direction == "BtoA":
    inputs, targets = [b_images, a_images]
else:
    raise Exception("invalid direction")

# synchronize seed for image operations so that we do the same operations to both
# input and output images
seed = random.randint(0, 2 ** 31 - 1)

# 图像预处理,翻转、改变形状
with tf.name_scope("input_images"):
    input_images = transform(inputs)
with tf.name_scope("target_images"):
    target_images = transform(targets)

# 获得输入图像、目标图像的batch块
paths_batch, inputs_batch, targets_batch = tf.train.batch([paths, input_images, target_images],
                                                          batch_size=batch_size)
steps_per_epoch = int(math.ceil(len(input_paths) / batch_size))

return Examples(
    paths=paths_batch,  # 输入的文件名块
    inputs=inputs_batch,  # 输入的图像块
    targets=targets_batch,  # 目标图像块
    count=len(input_paths),  # 数据集的大小
    steps_per_epoch=steps_per_epoch,  # batch的个数
)

图像预处理,翻转、改变形状

def transform(image):
r = image
if flip:
r = tf.image.random_flip_left_right(r, seed=seed)

# area produces a nice downscaling, but does nearest neighbor for upscaling
# assume we're going to be doing downscaling here
r = tf.image.resize_images(r, [scale_size, scale_size], method=tf.image.ResizeMethod.AREA)

offset = tf.cast(tf.floor(tf.random_uniform([2], 0, scale_size - CROP_SIZE + 1, seed=seed)), dtype=tf.int32)
if scale_size > CROP_SIZE:
    r = tf.image.crop_to_bounding_box(r, offset[0], offset[1], CROP_SIZE, CROP_SIZE)
elif scale_size < CROP_SIZE:
    raise Exception("scale size cannot be less than crop size")
return r

创建生成器,这是一个编码解码器的变种,输入输出均为:256*256*3, 像素值为[-1,1]

def create_generator(generator_inputs, generator_outputs_channels):
layers = []

# encoder_1: [batch, 256, 256, in_channels] => [batch, 128, 128, ngf]
with tf.variable_scope("encoder_1"):
    output = gen_conv(generator_inputs, ngf)  # ngf为第一个卷积层的卷积核核数量,默认为 64
    layers.append(output)

layer_specs = [
    ngf * 2,  # encoder_2: [batch, 128, 128, ngf] => [batch, 64, 64, ngf * 2]
    ngf * 4,  # encoder_3: [batch, 64, 64, ngf * 2] => [batch, 32, 32, ngf * 4]
    ngf * 8,  # encoder_4: [batch, 32, 32, ngf * 4] => [batch, 16, 16, ngf * 8]
    ngf * 8,  # encoder_5: [batch, 16, 16, ngf * 8] => [batch, 8, 8, ngf * 8]
    ngf * 8,  # encoder_6: [batch, 8, 8, ngf * 8] => [batch, 4, 4, ngf * 8]
    ngf * 8,  # encoder_7: [batch, 4, 4, ngf * 8] => [batch, 2, 2, ngf * 8]
    ngf * 8,  # encoder_8: [batch, 2, 2, ngf * 8] => [batch, 1, 1, ngf * 8]
]

# 卷积的编码器
for out_channels in layer_specs:
    with tf.variable_scope("encoder_%d" % (len(layers) + 1)):
        # 对最后一层使用激活函数
        rectified = lrelu(layers[-1], 0.2)
        # [batch, in_height, in_width, in_channels] => [batch, in_height/2, in_width/2, out_channels]
        convolved = gen_conv(rectified, out_channels)
        output = batchnorm(convolved)
        layers.append(output)

layer_specs = [
    (ngf * 8, 0.5),  # decoder_8: [batch, 1, 1, ngf * 8] => [batch, 2, 2, ngf * 8 * 2]
    (ngf * 8, 0.5),  # decoder_7: [batch, 2, 2, ngf * 8 * 2] => [batch, 4, 4, ngf * 8 * 2]
    (ngf * 8, 0.5),  # decoder_6: [batch, 4, 4, ngf * 8 * 2] => [batch, 8, 8, ngf * 8 * 2]
    (ngf * 8, 0.0),  # decoder_5: [batch, 8, 8, ngf * 8 * 2] => [batch, 16, 16, ngf * 8 * 2]
    (ngf * 4, 0.0),  # decoder_4: [batch, 16, 16, ngf * 8 * 2] => [batch, 32, 32, ngf * 4 * 2]
    (ngf * 2, 0.0),  # decoder_3: [batch, 32, 32, ngf * 4 * 2] => [batch, 64, 64, ngf * 2 * 2]
    (ngf, 0.0),  # decoder_2: [batch, 64, 64, ngf * 2 * 2] => [batch, 128, 128, ngf * 2]
]

# 卷积的解码器
num_encoder_layers = len(layers)  # 8
for decoder_layer, (out_channels, dropout) in enumerate(layer_specs):
    skip_layer = num_encoder_layers - decoder_layer - 1
    with tf.variable_scope("decoder_%d" % (skip_layer + 1)):
        if decoder_layer == 0:
            # first decoder layer doesn't have skip connections
            # since it is directly connected to the skip_layer
            input = layers[-1]
        else:
            input = tf.concat([layers[-1], layers[skip_layer]], axis=3)

        rectified = tf.nn.relu(input)
        # [batch, in_height, in_width, in_channels] => [batch, in_height*2, in_width*2, out_channels]
        output = gen_deconv(rectified, out_channels)
        output = batchnorm(output)

        if dropout > 0.0:
            output = tf.nn.dropout(output, keep_prob=1 - dropout)

        layers.append(output)

# decoder_1: [batch, 128, 128, ngf * 2] => [batch, 256, 256, generator_outputs_channels]
with tf.variable_scope("decoder_1"):
    input = tf.concat([layers[-1], layers[0]], axis=3)
    rectified = tf.nn.relu(input)
    output = gen_deconv(rectified, generator_outputs_channels)
    output = tf.tanh(output)
    layers.append(output)

return layers[-1]

创建判别器,输入生成的图像和真实的图像:两个[batch,256,256,3],元素值值[-1,1],输出:[batch,30,30,1],元素值为概率

def create_discriminator(discrim_inputs, discrim_targets):
n_layers = 3
layers = []

# 2x [batch, height, width, in_channels] => [batch, height, width, in_channels * 2]
input = tf.concat([discrim_inputs, discrim_targets], axis=3)

# layer_1: [batch, 256, 256, in_channels * 2] => [batch, 128, 128, ndf]
with tf.variable_scope("layer_1"):
    convolved = discrim_conv(input, ndf, stride=2)
    rectified = lrelu(convolved, 0.2)
    layers.append(rectified)

# layer_2: [batch, 128, 128, ndf] => [batch, 64, 64, ndf * 2]
# layer_3: [batch, 64, 64, ndf * 2] => [batch, 32, 32, ndf * 4]
# layer_4: [batch, 32, 32, ndf * 4] => [batch, 31, 31, ndf * 8]
for i in range(n_layers):
    with tf.variable_scope("layer_%d" % (len(layers) + 1)):
        out_channels = ndf * min(2 ** (i + 1), 8)
        stride = 1 if i == n_layers - 1 else 2  # last layer here has stride 1
        convolved = discrim_conv(layers[-1], out_channels, stride=stride)
        normalized = batchnorm(convolved)
        rectified = lrelu(normalized, 0.2)
        layers.append(rectified)

# layer_5: [batch, 31, 31, ndf * 8] => [batch, 30, 30, 1]
with tf.variable_scope("layer_%d" % (len(layers) + 1)):
    convolved = discrim_conv(rectified, out_channels=1, stride=1)
    output = tf.sigmoid(convolved)
    layers.append(output)

return layers[-1]

创建Pix2Pix模型,inputs和targets形状为:[batch_size, height, width, channels]

def create_model(inputs, targets):
with tf.variable_scope("generator"):
out_channels = int(targets.get_shape()[-1])
outputs = create_generator(inputs, out_channels)

# create two copies of discriminator, one for real pairs and one for fake pairs
# they share the same underlying variables
with tf.name_scope("real_discriminator"):
    with tf.variable_scope("discriminator"):
        # 2x [batch, height, width, channels] => [batch, 30, 30, 1]
        predict_real = create_discriminator(inputs, targets)  # 条件变量图像和真实图像

with tf.name_scope("fake_discriminator"):
    with tf.variable_scope("discriminator", reuse=True):
        # 2x [batch, height, width, channels] => [batch, 30, 30, 1]
        predict_fake = create_discriminator(inputs, outputs)  # 条件变量图像和生成的图像

# 判别器的损失,判别器希望V(G,D)尽可能大
with tf.name_scope("discriminator_loss"):
    # minimizing -tf.log will try to get inputs to 1
    # predict_real => 1
    # predict_fake => 0
    discrim_loss = tf.reduce_mean(-(tf.log(predict_real + EPS) + tf.log(1 - predict_fake + EPS)))

# 生成器的损失,生成器希望V(G,D)尽可能小
with tf.name_scope("generator_loss"):
    # predict_fake => 1
    # abs(targets - outputs) => 0
    gen_loss_GAN = tf.reduce_mean(-tf.log(predict_fake + EPS))
    gen_loss_L1 = tf.reduce_mean(tf.abs(targets - outputs))
    gen_loss = gen_loss_GAN * gan_weight + gen_loss_L1 * l1_weight

# 判别器训练
with tf.name_scope("discriminator_train"):
    # 判别器需要优化的参数
    discrim_tvars = [var for var in tf.trainable_variables() if var.name.startswith("discriminator")]
    # 优化器定义
    discrim_optim = tf.train.AdamOptimizer(lr, beta1)
    # 计算损失函数对优化参数的梯度
    discrim_grads_and_vars = discrim_optim.compute_gradients(discrim_loss, var_list=discrim_tvars)
    # 更新该梯度所对应的参数的状态,返回一个op
    discrim_train = discrim_optim.apply_gradients(discrim_grads_and_vars)

# 生成器训练
with tf.name_scope("generator_train"):
    with tf.control_dependencies([discrim_train]):
        # 生成器需要优化的参数列表
        gen_tvars = [var for var in tf.trainable_variables() if var.name.startswith("generator")]
        # 定义优化器
        gen_optim = tf.train.AdamOptimizer(lr, beta1)
        # 计算需要优化的参数的梯度
        gen_grads_and_vars = gen_optim.compute_gradients(gen_loss, var_list=gen_tvars)
        # 更新该梯度所对应的参数的状态,返回一个op
        gen_train = gen_optim.apply_gradients(gen_grads_and_vars)

'''
  在采用随机梯度下降算法训练神经网络时,使用 tf.train.ExponentialMovingAverage 滑动平均操作的意义在于
提高模型在测试数据上的健壮性(robustness)。tensorflow 下的 tf.train.ExponentialMovingAverage 需要
提供一个衰减率(decay)。该衰减率用于控制模型更新的速度。该衰减率用于控制模型更新的速度,
ExponentialMovingAverage 对每一个(待更新训练学习的)变量(variable)都会维护一个影子变量
(shadow variable)。影子变量的初始值就是这个变量的初始值,
    shadow_variable=decay×shadow_variable+(1−decay)×variable
'''
ema = tf.train.ExponentialMovingAverage(decay=0.99)
update_losses = ema.apply([discrim_loss, gen_loss_GAN, gen_loss_L1])

#
global_step = tf.train.get_or_create_global_step()
incr_global_step = tf.assign(global_step, global_step + 1)

return Model(
    predict_real=predict_real,  # 条件变量(输入图像)和真实图像之间的概率值,形状为;[batch,30,30,1]
    predict_fake=predict_fake,  # 条件变量(输入图像)和生成图像之间的概率值,形状为;[batch,30,30,1]
    discrim_loss=ema.average(discrim_loss),  # 判别器损失
    discrim_grads_and_vars=discrim_grads_and_vars,  # 判别器需要优化的参数和对应的梯度
    gen_loss_GAN=ema.average(gen_loss_GAN),  # 生成器的损失
    gen_loss_L1=ema.average(gen_loss_L1),  # 生成器的 L1损失
    gen_grads_and_vars=gen_grads_and_vars,  # 生成器需要优化的参数和对应的梯度
    outputs=outputs,  # 生成器生成的图片
    train=tf.group(update_losses, incr_global_step, gen_train),  # 打包需要run的操作op
)

保存图像

def save_images(output_dir, fetches, step=None):
image_dir = os.path.join(output_dir, "images")
if not os.path.exists(image_dir):
os.makedirs(image_dir)

filesets = []
for i, in_path in enumerate(fetches["paths"]):
    name, _ = os.path.splitext(os.path.basename(in_path.decode("utf8")))
    fileset = {"name": name, "step": step}
    for kind in ["inputs", "outputs", "targets"]:
        filename = name + "-" + kind + ".png"
        if step is not None:
            filename = "%08d-%s" % (step, filename)
        fileset[kind] = filename
        out_path = os.path.join(image_dir, filename)
        contents = fetches[kind][i]
        with open(out_path, "wb") as f:
            f.write(contents)
    filesets.append(fileset)
return filesets

将结果写入HTML网页

def append_index(output_dir, filesets, step=False):
index_path = os.path.join(output_dir, "index.html")
if os.path.exists(index_path):
index = open(index_path, "a")
else:
index = open(index_path, "w")
index.write("

")
if step:
index.write("")
index.write("")
for fileset in filesets:
    index.write("<tr>")

    if step:
        index.write("<td>%d</td>" % fileset["step"])
    index.write("<td>%s</td>" % fileset["name"])

    for kind in ["inputs", "outputs", "targets"]:
        index.write("<td><img src='images/%s'></td>" % fileset[kind])

    index.write("</tr>")
return index_path

转变图像的尺寸、并且将[0,1]--->[0,255]

def convert(image):
if aspect_ratio != 1.0:
# upscale to correct aspect ratio
size = [CROP_SIZE, int(round(CROP_SIZE * aspect_ratio))]
image = tf.image.resize_images(image, size=size, method=tf.image.ResizeMethod.BICUBIC)

# 将数据的类型转换为8位无符号整型
return tf.image.convert_image_dtype(image, dtype=tf.uint8, saturate=True)

主函数

def train():
# 设置随机数种子的值
global seed
if seed is None:
seed = random.randint(0, 2 ** 31 - 1)

tf.set_random_seed(seed)
np.random.seed(seed)
random.seed(seed)

# 创建目录
if not os.path.exists(train_output_dir):
    os.makedirs(train_output_dir)

# 加载数据集,得到输入数据和目标数据并把范围变为 :[-1,1]
examples = load_examples(train_input_dir)
print("load successful ! examples count = %d" % examples.count)

# 创建模型,inputs和targets是:[batch_size, height, width, channels]
# 返回值:
model = create_model(examples.inputs, examples.targets)
print("create model successful!")

# 图像处理[-1, 1] => [0, 1]
inputs = deprocess(examples.inputs)
targets = deprocess(examples.targets)
outputs = deprocess(model.outputs)

# 把[0,1]的像素点转为RGB值:[0,255]
with tf.name_scope("convert_inputs"):
    converted_inputs = convert(inputs)
with tf.name_scope("convert_targets"):
    converted_targets = convert(targets)
with tf.name_scope("convert_outputs"):
    converted_outputs = convert(outputs)

# 对图像进行编码以便于保存
with tf.name_scope("encode_images"):
    display_fetches = {
        "paths": examples.paths,
        # tf.map_fn接受一个函数对象和集合,用函数对集合中每个元素分别处理
        "inputs": tf.map_fn(tf.image.encode_png, converted_inputs, dtype=tf.string, name="input_pngs"),
        "targets": tf.map_fn(tf.image.encode_png, converted_targets, dtype=tf.string, name="target_pngs"),
        "outputs": tf.map_fn(tf.image.encode_png, converted_outputs, dtype=tf.string, name="output_pngs"),
    }

with tf.name_scope("parameter_count"):
    parameter_count = tf.reduce_sum([tf.reduce_prod(tf.shape(v)) for v in tf.trainable_variables()])

# 只保存最新一个checkpoint
saver = tf.train.Saver(max_to_keep=20)

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)
    print("parameter_count =", sess.run(parameter_count))
    if max_epochs is not None:
        max_steps = examples.steps_per_epoch * max_epochs  # 400X200=80000

    # 因为是从文件中读取数据,所以需要启动start_queue_runners()
    # 这个函数将会启动输入管道的线程,填充样本到队列中,以便出队操作可以从队列中拿到样本。
    coord = tf.train.Coordinator()
    threads = tf.train.start_queue_runners(coord=coord)

    # 运行训练集
    print("begin trainning......")
    print("max_steps:", max_steps)
    start = time.time()
    for step in range(max_steps):
        def should(freq):
            return freq > 0 and ((step + 1) % freq == 0 or step == max_steps - 1)

        print("step:", step)

        # 定义一个需要run的所有操作的字典
        fetches = {
            "train": model.train
        }

        # progress_freq为 50,每50次计算一次三个损失,显示进度
        if should(progress_freq):
            fetches["discrim_loss"] = model.discrim_loss
            fetches["gen_loss_GAN"] = model.gen_loss_GAN
            fetches["gen_loss_L1"] = model.gen_loss_L1

        # display_freq为 50,每50次保存一次输入、目标、输出的图像
        if should(display_freq):
            fetches["display"] = display_fetches

        # 运行各种操作,
        results = sess.run(fetches)

        # display_freq为 50,每50次保存输入、目标、输出的图像
        if should(display_freq):
            print("saving display images")
            filesets = save_images(train_output_dir, results["display"], step=step)
            append_index(train_output_dir, filesets, step=True)

            # progress_freq为 50,每50次打印一次三种损失的大小,显示进度
        if should(progress_freq):
            # global_step will have the correct step count if we resume from a checkpoint
            train_epoch = math.ceil(step / examples.steps_per_epoch)
            train_step = (step - 1) % examples.steps_per_epoch + 1
            rate = (step + 1) * batch_size / (time.time() - start)
            remaining = (max_steps - step) * batch_size / rate
            print("progress  epoch %d  step %d  image/sec %0.1f  remaining %dm" % (
            train_epoch, train_step, rate, remaining / 60))
            print("discrim_loss", results["discrim_loss"])
            print("gen_loss_GAN", results["gen_loss_GAN"])
            print("gen_loss_L1", results["gen_loss_L1"])

        # save_freq为500,每500次保存一次模型
        if should(save_freq):
            print("saving model")
            saver.save(sess, os.path.join(train_output_dir, "model"), global_step=step)

测试

def test():
# 设置随机数种子的值
global seed
if seed is None:
seed = random.randint(0, 2 ** 31 - 1)

tf.set_random_seed(seed)
np.random.seed(seed)
random.seed(seed)

# 创建目录
if not os.path.exists(test_output_dir):
    os.makedirs(test_output_dir)
if checkpoint is None:
    raise Exception("checkpoint required for test mode")

# disable these features in test mode
scale_size = CROP_SIZE
flip = False

# 加载数据集,得到输入数据和目标数据
examples = load_examples(test_input_dir)
print("load successful ! examples count = %d" % examples.count)

# 创建模型,inputs和targets是:[batch_size, height, width, channels]
model = create_model(examples.inputs, examples.targets)
print("create model successful!")

# 图像处理[-1, 1] => [0, 1]
inputs = deprocess(examples.inputs)
targets = deprocess(examples.targets)
outputs = deprocess(model.outputs)

# 把[0,1]的像素点转为RGB值:[0,255]
with tf.name_scope("convert_inputs"):
    converted_inputs = convert(inputs)
with tf.name_scope("convert_targets"):
    converted_targets = convert(targets)
with tf.name_scope("convert_outputs"):
    converted_outputs = convert(outputs)

# 对图像进行编码以便于保存
with tf.name_scope("encode_images"):
    display_fetches = {
        "paths": examples.paths,
        # tf.map_fn接受一个函数对象和集合,用函数对集合中每个元素分别处理
        "inputs": tf.map_fn(tf.image.encode_png, converted_inputs, dtype=tf.string, name="input_pngs"),
        "targets": tf.map_fn(tf.image.encode_png, converted_targets, dtype=tf.string, name="target_pngs"),
        "outputs": tf.map_fn(tf.image.encode_png, converted_outputs, dtype=tf.string, name="output_pngs"),
    }

sess = tf.InteractiveSession()
saver = tf.train.Saver(max_to_keep=1)

ckpt = tf.train.get_checkpoint_state(checkpoint)
saver.restore(sess,ckpt.model_checkpoint_path)

start = time.time()

coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord)
for step in range(examples.count):
    results = sess.run(display_fetches)
    filesets = save_images(test_output_dir, results)
    for i, f in enumerate(filesets):
        print("evaluated image", f["name"])
    index_path = append_index(test_output_dir, filesets)
print("wrote index at", index_path)
print("rate", (time.time() - start) / max_steps)

if name == '__main__':
train()
#test()

stepname input output target

1个回答

造成分辨率不一致应该是系统或者显卡设置了缩放功能

hujb48
大滨滨 回复weixin_39416561: 如果用sift flow算法是可以匹配比例,但是好像不能满足pix2pix的input要求
一年多之前 回复
hujb48
大滨滨 回复weixin_39416561: 感觉好像是因为卷积神经网络的原因,要在上采样的网络上进行考虑
一年多之前 回复
weixin_39416561
lyhsdy 回复hujb48: 先测试INPUT和OUTPUT的比例,然后通过比例进行匹配计算
一年多之前 回复
weixin_39416561
lyhsdy 先测试INPUT和OUTPUT的比例,然后通过比例进行匹配计算
一年多之前 回复
hujb48
大滨滨 我就是想去做成就是INPUT和OUTPUT分辨率不一样的成对图像。
一年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
其他相关推荐
pix2pix运行后各参数的含义及变化

pix2pix的代码中下列参数个代表什么含义,本人小白一个,程序运行出来看不太懂: epoch step image/sec remaining discrim_loss gen_loss_GAN gen_loss_L1 其中discrim_loss与gen_loss_GAN应该如何变化,变化范围大概多少,逐渐增大还是减小,我运行不同的数据集,有的discrim_loss在增大,而有的在减小,gen_loss_L1也存在这样的问题,这是为什么啊,求大神帮帮忙 为什么我生成的损失率曲线图是这样子的![图片说明](https://img-ask.csdn.net/upload/202001/20/1579488564_881713.png)![图片说明](https://img-ask.csdn.net/upload/202001/20/1579488575_81777.png)

pix4D的数据处理问题?

pix4D如何处理航拍视频啊?为什么我处理来会提示80%以上的图像坐标和相机模型是相同的,因此,相应的地理标签将不被采用,这是什么原因? pix4D如何进行控制点的标记? pix4D如何建立3D模型? 请各位赐教,刚接触这个软件,存在太多问题,谢谢

用JAVA将彩色图像变为灰度图像

public int[] toGray(int[] pix, int iw, int ih) { ColorModel cm = ColorModel.getRGBdefault(); int r, g, b, gray; for(int i = 0; i < iw*ih; i++) { r = cm.getRed(pix[i]); g = cm.getGreen(pix[i]); b = cm.getBlue(pix[i]); gray =(int)((r + g + b) / 3); pix[i] = 255 << 24|gray << 16|gray << 8|gray; } return pix; } 这段代码中pix[i] = 255 << 24|gray << 16|gray << 8|gray是什么意思?

用Verilog設計自适应阈值化产生图像二值化,用modelsim模拟波形结果非正确波形

一、 問題: 使用Verilog语法撰写,并用自适应阈值化(Adaptive Threshold Engine,ATE)产生图像二值化,由于初学1个月左右,有几点问题: 1. 模拟结果64个像素(pixel)在执行完成会合成一个区块(block) ,正常执行须执行完成24行与完成24区块, 2. 使用modelsim模拟的结果不如预期结果,clk与reset触发后,pix_data负缘输入,bin与threshold正缘输出。 (1) 但是pix_data预期要1,2,...,64为block 1 input; 实际错误结果是24,2d236,...未依照结果输出。 (2) bin输出延迟设定为1周期(latency=1),预期要1,2,...,64为block 1 input,实际错误结果未依照结果输出,波形没有从1开始。 (3) threshold跟pix_data、 bin有关,会由前面block 1 input输出为block 1 threshold,实际错误结果:00是block 1 threshold,77是是block 2 threshold,由于pix_data、 bin一开始错误,未依照结果输出。 二、代碼ate.v ``` module ate(clk,reset,pix_data,bin,threshold); input clk; input reset; input [7:0] pix_data; output bin; output [7:0] threshold; reg [7:0] threshold; reg bin; reg [7:0] data [63:0]; reg [5:0]counter; //reg [6:0] count; reg [7:0]min0; reg [7:0]max0; //min, max is 16進位 reg [4:0]block; //reg [4:0] block_count; block is 24; integer i; always@(posedge clk or posedge reset) begin if(reset) begin block <= 5'd0; end else begin if((counter == 6'd63)&&(block == 5'd5)) begin block <= 5'd0; end else if(counter == 6'd63) begin block <= block + 5'd1; end end end always@(posedge clk or posedge reset) begin if(reset) begin counter <= 6'd0; end else begin counter <= counter + 6'd1; end end always@(posedge clk or posedge reset) begin if(reset) begin for(i = 0; i < 64; i = i + 1) begin data[i] <= 8'd0; end end else begin data[counter] <= pix_data; end end always@(posedge clk or posedge reset) begin if(reset) begin max0 <= 8'd0; end else begin if(counter == 6'd0) begin max0 <= pix_data; end else if(max0 < pix_data) begin max0 <= pix_data; end end end always@(posedge clk or posedge reset) begin if(reset) begin min0 <= 8'hff; end else begin if(counter == 6'd0) begin min0 <= pix_data; end else if(min0 > pix_data) //(min0 > pix_data) begin min0 <= pix_data; end end end //output wire dout; wire [7:0]avg; wire [7:0]thout; wire [8:0]sum; assign sum = {1'b0, min0} + {1'b0, max0}; assign avg = (sum[0]) ? (sum + 9'd01) >> 1 : sum >> 1; assign dout = (((block == 5'd1)||(block == 5'd0))) ? 1'b0 : ((counter == 6'd0)&&(data[0] >= avg)) ? 1'b1 : ((counter != 6'd0)&&(data[counter] >= threshold)) ? 1'b1 : 1'b0; assign thout = (((block == 5'd1)||(block == 5'd0))) ? 8'd0 : avg; always@(posedge clk or posedge reset) begin if(reset) begin bin <= 1'b0; end else begin bin <= dout; end end always@(posedge clk or posedge reset) begin if(reset) begin threshold <= 8'd0; end else begin if(counter == 6'd0) begin threshold <= thout; end end end endmodule ``` 三、錯報訊息: 有确认过testbench确定无问题,但是在修正程式仍无法改上此情形,因此我想询问有何么方式可以改善此情况,谢谢。 产生结果为下图: ![图片说明](https://img-ask.csdn.net/upload/201901/01/1546341857_144738.png) 四、方法 设计方法: 因设计ATE接受的输入影像大小为48x32(共分为6x4区块),一个区块固定为8x8个点。影像输入顺序是以区为单位依序输入。执行Threshold处理时,是以一个区块作为单位,而最左边及最右边兩行不需处理,一律输出0 (bin及threshold皆是),如: 0,6,12,18区块及5, 11,17,23区块皆不需处理。下图为输入影像区块编号顺序。 ![图片说明](https://img-ask.csdn.net/upload/201901/01/1546341878_352139.png) Adaptive Threshold目的是将一灰阶影像的前景及背景区分出來,对于该影像区块的每一个点,若大于或等于该区块门槛值(threshold)则输出1,反之则输出0。而Adaptive threshold表示此threshold是经由计算所得。 ATE电路的threshold计算方法采用单一8x8区块中之最大數值及最小數值的平均值,即threshold = (Max + Min) / 2,若threshold有小數,则采无条件进位。 对于每一点输出,其计算公式如下: bin=1 if pix_data >= threshold bin=0 if pix_data < threshold 设计该区块(8*8)之最大值为192,最小值为48,则threshold=(192+48)/2=120。后续区块内的pix_data >= threshold,bin输出为1;pix_data < threshold,bin输出为0。 ![图片说明](https://img-ask.csdn.net/upload/201901/01/1546341898_983395.png) 实际预期波形结果:(输入与输出波形顺序) ![图片说明](https://img-ask.csdn.net/upload/201901/01/1546341914_278764.png)

思科PIX515E开机进入不了,本人新手求大神解决,谢啦!

公司有个PIX515E,下午突然断网了,我重启然后用console口直连发现直连也进不去。我发现前面的ACT灯没有亮。求高手帮忙想想办法,或者说最有可能是什么故障导致的。图片为我直连时候的截图。卡在那里就不去,然后没反应![图片说明](https://img-ask.csdn.net/upload/201501/26/1422278792_646663.jpg)

linux的V4l2可以采集到H264码流数据吗?

我在尝试使用Linux的V4l2采集摄像头数据并显示到屏幕中,之前采用的是 V4L2_PIX_FMT_YUYV 格式采集数据的,但是觉得使用ffmpeg解码H264的 速度可能会更快,但是在 <linux/videodev2.h> 文件中并没能找到 V4L2_PIX_FMT_H264 格式,可以用其他格式代替?或者有其他的办法获取 H264码流?

python小程序将 .tif格式图像转换为灰度图但一直报错,求高手解答

代码在这很简单,最初也成功过,现在又不行了,我用了PIL和libtiff,但为什么arcpy.Minus只能存储为.tif?而且再次读入.tif文件时又一直报错,报错截图在最后,麻烦大神们了! # -*- coding: utf-8 -*- from PIL import Image from PIL import ImageDraw from libtiff import TIFF import arcpy from arcpy import env env.workspace = "E:\\work\\cppservice\\RasterCalc" #工作空间 inRaster1 = "E:\\2013.png" inRaster2 = "E:\\2020.png" arcpy.CheckOutExtension("3D") arcpy.Minus_3d(inRaster1,inRaster2,"E:\w.tif")#minus代表两幅图像相减,输出目前看来只能是tif格式,为什么? im = Image.open('E:/w.tif') #再打开tif图像 im = im.convert('L')#彩图转换为灰度图 width, height = im.size#以下为统计像素点的值 pw = width pix = im.load() a = [0.00]*3 #计算三种值的像素个数 for w in xrange(width): for h in xrange(height): p = pix[w,h] if p > 220: a[0]+=1 elif p < 35: a[1]+=1 else: a[2]+=1 print ("剧烈变化地区所占百分比: %.3f %%"%(a[0]/(width*height)*100)) print ("无变化区域所占百分比: %.3f %%"%(a[1]/(width*height)*100)) print ("适度变化区域百分比: %.3f %%"%(a[2]/(width*height)*100))#%%输出%号 报错如下图 ![图片说明](https://img-ask.csdn.net/upload/201510/11/1444575495_478515.png)

最新的 ffmpeg 2.8 其实连yuy2数据包都不能正确转换

说了你也不相信,我用 directx 采集到的数据是从web camera来的 yuy2 数据,我用自己写的转换程序可以成功转换正确的图像rgb24, yuy2 -> rgb24 -> I420 都可以,但是用ffmpeg的sws__scale 怎么也无法正确转换。 sws__scale 的解码过程如下 void scaleYUY2toI420(const void *pSrc, int widthSrc, int heightSrc, void *pDest, int widthDest, int heightDest, bool bQualityImportant/* = false*/) { struct SwsContext *pctx; AVPicture picSrc = { 0 }; AVPicture picDst = { 0 }; enum AVPixelFormat fmtSrc = AV_PIX_FMT_YUYV422; enum AVPixelFormat fmtDst = AV_PIX_FMT_YUV420P; avpicture_fill(&picSrc, (uint8_t*)pSrc, fmtSrc, widthSrc, heightSrc); // avpicture_fill(&picDst, (uint8_t*)pDest, fmtDst, widthDest, heightDest); pctx = sws_getContext(widthSrc, heightSrc, fmtSrc, widthDest, heightDest, fmtDst, bQualityImportant ? SWS_BICUBIC : SWS_POINT, NULL, NULL, NULL); if (pctx == NULL) return; sws_scale(pctx, picSrc.data, picSrc.linesize, 0, heightSrc, picDst.data, picDst.linesize); sws_freeContext(pctx); } 问题在哪里始终不得要领,希望专家们不吝赐教。 为了验证问题,我用 ffmpeg 转换 rgb24 -> I420每问题,是不是ffmpeg不支持 yuy2 packed 包到 i420?但是我看它的像素格式定义, AV_PIX_FMT_YUYV422 排在最前面啊

HALCON是如何做到在一个比图片小的窗口中得到图片每个像素的灰度值的?在VC中实现这样的效果吗?

在HALCON中读入一张图片,大小2448*2024,将该图片显示在宽、高均为图片尺寸1/4的窗口中。 将鼠标放在窗口中的图片上移动,屏幕的右下角即可显示每个像素的灰度值。 虽然,此处窗口的尺寸比图片的小,但是依然能够显示每个像素的坐标及灰度值。 我的疑问是: 1、在小窗口中显示图片,不是将图片压缩为与窗口同大小的尺寸了吗?即图片的尺寸也应该变为原来的1/4啊(612*512),为什么还能得到原图中像素坐! 标大于612和512的每个像素的灰度值?这一功能实现的原理是什么? 2、如果在VC的界面中,用PIC CONTROL来显示图片,如何实现上述HALCON的功能,即窗口虽然比较图片小,但依然可以在窗口中,根据鼠标的位置,得到原图中每个像素的灰度值。 往高手给与指点。非常感谢! 下面是HALCON代码: ``` dev_update_off () read_image (ImageOrigion, 'logok/2.bmp') get_image_size (ImageOrigion, Width, Height) dev_close_window () dev_open_window (0, 0, Width/4, Height/4, 'black', WindowHandle) set_display_font (WindowHandle, 16, 'mono', 'true', 'false') dev_display(ImageOrigion) ``` 所打开的窗口如下图: ![图片说明](https://img-ask.csdn.net/upload/201910/20/1571527891_345888.jpg) 在窗口中的图片上移动鼠标,屏幕右下方显示,可以得到原图中每个像素的灰度值,如下图: ![图片说明](https://img-ask.csdn.net/upload/201910/20/1571528148_775523.png)

V4L2采集视频是花的。

![图片说明](https://img-ask.csdn.net/upload/201506/05/1433495727_3981.png) 如图所示,应该是图像帧的问题,设置帧格式代码如下 //设置帧的格式 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = 640; fmt.fmt.pix.height = 480; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; 请问出现这种问题的原因是什么呢?

我用c++写了个图像显示程序,为什么显示出来是这样的?

用c++写了个图像显示程序,但是显示出来的图像是这样的![图片说明](https://img-ask.csdn.net/upload/201905/27/1558941977_691414.png) 有没有童鞋帮我看看哪里出错了,,,万分感激! 这是我的代码 #include<iostream> #include<Windows.h> #include<malloc.h> #include<stdlib.h> #include<stdio.h> #include<string.h> using namespace std; //显示位图文件头信息 void showBmpHead(BITMAPFILEHEADER pBmpHead) { cout<<"位图文件头:"<<endl; cout<<"文件大小:"<<pBmpHead.bfSize<<endl; cout<<"保留字_1:"<<pBmpHead.bfReserved1<<endl; cout<<"保留字_2:"<<pBmpHead.bfReserved2<<endl; cout<<"实际位图数据的偏移字节数:"<<pBmpHead.bfOffBits<<endl<<endl; } void showBmpInforHead(tagBITMAPINFOHEADER pBmpInforHead) { cout<<"位图信息头:"<<endl; cout<<"结构体的长度:"<<pBmpInforHead.biSize<<endl; cout<<"位图宽:"<<pBmpInforHead.biWidth<<endl; cout<<"位图高:"<<pBmpInforHead.biHeight<<endl; cout<<"biPlanes平面数:"<<pBmpInforHead.biPlanes<<endl; cout<<"biBitCount采用颜色位数:"<<pBmpInforHead.biBitCount<<endl; cout<<"压缩方式:"<<pBmpInforHead.biCompression<<endl; cout<<"biSizeImage实际位图数据占用的字节数:"<<pBmpInforHead.biSizeImage<<endl; cout<<"X方向分辨率:"<<pBmpInforHead.biXPelsPerMeter<<endl; cout<<"Y方向分辨率:"<<pBmpInforHead.biYPelsPerMeter<<endl; cout<<"使用的颜色数:"<<pBmpInforHead.biClrUsed<<endl; cout<<"重要颜色数:"<<pBmpInforHead.biClrImportant<<endl; } void main () { char fileName[30]; //定义打开图像名字 char *buf; //定义文件读取缓冲区 char *p; int r,g,b,pix; HWND wnd; //窗口句柄 HDC dc; //绘图设备环境句柄 FILE *fp; //定义文件指针 FILE *fpw; //定义保存文件指针 DWORD w,h; //定义读取图像的长和宽 DWORD bitSize; //定义图像的大小 BITMAPFILEHEADER bf; //图像文件头 BITMAPINFOHEADER bi; //图像文件头信息 cout<<"请输入要打开文件的名字:(如:e:\\1.bmp)"; cin>>fileName; if((fp=fopen(fileName,"rb"))==NULL) { cout<<"文件未找到!"; exit(0); } fread(&bf,sizeof(BITMAPFILEHEADER),1,fp);//读取BMP文件头文件 showBmpHead(bf); fread(&bi,sizeof(BITMAPINFOHEADER),1,fp);//读取BMP文件头文件信息 showBmpInforHead(bi); w=bi.biWidth; //获取图像的宽 h=bi.biHeight; //获取图像的高 bitSize=bi.biSizeImage; //获取图像的size buf=(char*)malloc(w*h*3); //分配缓冲区大小 fseek(fp,long(40+14+sizeof(RGBQUAD)),0);//定位到像素起始位置 fread(buf,1,w*h*3,fp); //开始读取数据 wnd=GetForegroundWindow(); //获取窗口句柄 dc=GetDC(wnd); //获取绘图设备 DWORD x=440; DWORD y=160;//图片显示的左上角点 p=buf; for(DWORD j=0;j<h;j++) { for(DWORD i=0;i<w;i++) { b=*p++;g=*p++;r=*p++; pix=RGB(r,g,b); SetPixel(dc,x+i,y+h-j,pix); } } fpw=fopen("LenaSaved.bmp","wb"); fwrite(&bf,sizeof(BITMAPFILEHEADER),1,fpw); //写入文件头 fwrite(&bi,sizeof(BITMAPINFOHEADER),1,fpw); //写入文件头信息 p=buf; for( DWORD j=0;j<h;j++) { for(DWORD i=0;i<w*3;i++) { fwrite(p++,1,1,fpw); } } fclose(fpw); fclose(fp); //return fp; system("pause"); }

在Go中读取图像

<div class="post-text" itemprop="text"> <pre><code>func (sticky *Sticky) DrawImage(W, H int) (img *image, err error) { myImage := image.NewRGBA(image.Rect(0, 0, 10, 25)) myImage.Pix[0] = 55 // 1st pixel red myImage.Pix[1] = 155 // 1st pixel green return myImage ,nil } </code></pre> <p>I am creating an image. I want to read the existing Image and return in this Function. How I can I do that?</p> </div>

用 ffmpeg命令行工具实现 屏幕与摄像头图像叠加(摄像头图像叠加上屏幕图右下角) 后推流命令,发现会卡,怎么解决呢?

问题:用 ffmpeg命令行工具实现 屏幕与摄像头图像叠加(摄像头图像叠加上屏幕图右下角) 后推流,发现会卡,怎么解决呢? 我的命令:ffmpeg -f gdigrab -framerate 30 -video_size 1920x1080 -i desktop -f dshow -framerate 30 -video_size 640x480 -i video="HD USB Camera" -filter_complex "overlay=main_w-overlay_w-10:main_h-overlay_h-10" -c:v libx264 -r 30 -b:v 1500k -pix_fmt yuv420p -tune zerolatency -preset ultrafast -f flv -y "rtmp://localhost/live/demo" 这里 "HD USB Camera" 是我的相机名称。 我发现跟命令中输入源的顺序有关,但是图像叠加是默认第一输入是背景图,第二输入是前景图的,所以若更换顺序,虽然不卡了,但却不能实现叠加效果,怎么办呢??另外因为某些原因我这里一定是使用 gdigrab 来捕获桌面的。

Qt图片缩小到一定程度再点放大还是缩小?

float x,y; pix=*(ui->board2->pixmap()); x=pix.height(); y=pix.width(); pix= pix.scaled(x/1.5,y/1.5,Qt::KeepAspectRatio); ui->board2->setPixmap(pix); 这是缩小部分的代码 float x,y; pix=*(ui->board2->pixmap()); x=pix.height(); y=pix.width(); pix= pix.scaled(x*1.5,y*1.5,Qt::KeepAspectRatio); ui->board2->setPixmap(pix); 放大的 当图片缩小几次再点击放大图片还是缩小,这是为什么

在arm上利用Qt采集视频图像,能够保存采集的视频图像

我使用的是usb免驱摄像头,现在已经实现实时显示图像,并能够拍照保存,但无法实现保存视频。 以下是本程序的相关代码 # main.cpp ``` #include "camera.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); camera w; w.show(); return a.exec(); } ``` # camera.cpp ``` #include "camera.h" #include "ui_camera.h" #include <QDate> #include <QTime> void yuv422to420p(char *yuv422buf, char *yuv420pbuf, int width, int height) { char *src, *dest, *dest2; int i, j; src = yuv422buf; dest = yuv420pbuf; for (i = 0; i < width * height * 2; i++) { if (i % 2 != 0) { continue; } *dest++ = *(src + i); } src = yuv422buf; dest = yuv420pbuf + width * height; dest2 = dest + (width * height) / 4; for (i = 0; i < height; i += 2) { for (j = 1; j < width * 2; j += 4) { *dest++ = *(src + i * width * 2 + j); *dest2++ = *(src + i * width * 2 + j + 2); } } } /* yuv格式转换为rgb格式的算法处理函数 */ int convert_yuv_to_rgb_pixel(int y, int u, int v) { unsigned int pixel32 = 0; unsigned char *pixel = (unsigned char *)&pixel32; int r, g, b; r = y + (1.370705 * (v-128)); g = y - (0.698001 * (v-128)) - (0.337633 * (u-128)); b = y + (1.732446 * (u-128)); if(r > 255) r = 255; if(g > 255) g = 255; if(b > 255) b = 255; if(r < 0) r = 0; if(g < 0) g = 0; if(b < 0) b = 0; pixel[0] = r ; pixel[1] = g ; pixel[2] = b ; return pixel32; } /* yuv格式转换为rgb格式 */ int convert_yuv_to_rgb_buffer(unsigned char *yuv, unsigned char *rgb, unsigned int width, unsigned int height) { unsigned int in, out = 0; unsigned int pixel_16; unsigned char pixel_24[3]; unsigned int pixel32; int y0, u, y1, v; for(in = 0; in < width * height * 2; in += 4) { pixel_16 = yuv[in + 3] << 24 | yuv[in + 2] << 16 | yuv[in + 1] << 8 | yuv[in + 0]; y0 = (pixel_16 & 0x000000ff); u = (pixel_16 & 0x0000ff00) >> 8; y1 = (pixel_16 & 0x00ff0000) >> 16; v = (pixel_16 & 0xff000000) >> 24; pixel32 = convert_yuv_to_rgb_pixel(y0, u, v); pixel_24[0] = (pixel32 & 0x000000ff); pixel_24[1] = (pixel32 & 0x0000ff00) >> 8; pixel_24[2] = (pixel32 & 0x00ff0000) >> 16; rgb[out++] = pixel_24[0]; rgb[out++] = pixel_24[1]; rgb[out++] = pixel_24[2]; pixel32 = convert_yuv_to_rgb_pixel(y1, u, v); pixel_24[0] = (pixel32 & 0x000000ff); pixel_24[1] = (pixel32 & 0x0000ff00) >> 8; pixel_24[2] = (pixel32 & 0x00ff0000) >> 16; rgb[out++] = pixel_24[0]; rgb[out++] = pixel_24[1]; rgb[out++] = pixel_24[2]; } return 0; } int camera::camera_init() { int ret=0,i=0,count=0; struct v4l2_capability cap; //视频设备的功能,对应命令VIDIOC_QUERYCAP struct v4l2_fmtdesc fmtdesc; //视频格式描述符类型 struct v4l2_format format; //帧的格式,如宽度,高度等,对应命令VIDIOC_G_FMT、VIDIOC_S_FMT等 struct v4l2_requestbuffers reqbuf; //向驱动申请帧缓冲请求,包含申请的个数,对应命令VIDIOC_REQBUFS struct v4l2_buffer buf; //驱动中的一帧图像缓存,对应命令VIDIOC_QUERYBUF fmtdesc.index = 0; fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //传输流类型 ret = ::ioctl(fd, VIDIOC_G_FMT, &format); //'VIDIOC_G_FMT'——读取当前驱动的视频捕获格式 if(ret < 0){ perror("VIDIOC_G_FMT"); exit(1); } printf("width:%d\n", format.fmt.pix.width); printf("height:%d\n", format.fmt.pix.height); printf("pixelformat:%x\n", format.fmt.pix.pixelformat); printf("field:%x\n", format.fmt.pix.field); printf("bytesperline:%d\n", format.fmt.pix.bytesperline); printf("sizeimage:%d\n", format.fmt.pix.sizeimage); printf("colorspace:%d\n", format.fmt.pix.colorspace); format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; format.fmt.pix.width = 640; format.fmt.pix.height = 480; format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; ret = ::ioctl(fd, VIDIOC_S_FMT, &format); if(ret < 0){ fprintf(stderr, "Not support jepg"); perror("VIDIOC_S_FMT"); exit(1); } reqbuf.count = 3; reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; reqbuf.memory = V4L2_MEMORY_MMAP; ret = ::ioctl(fd, VIDIOC_REQBUFS, &reqbuf); if(ret < 0){ perror("VIDIOC_REQBUFS"); exit(1); } bufinf = (struct bufinfor *)calloc(reqbuf.count, sizeof(struct bufinfor)); if(!bufinf){ perror("calloc"); exit(1); } for(count = 0; count < reqbuf.count; count++){ buf.index = count; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; ret = ::ioctl(fd, VIDIOC_QUERYBUF, &buf); if(ret < 0){ perror("VIDIOC_REQBUFS"); exit(1); } bufinf[buf.index].length = buf.length; bufinf[buf.index].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset); if(!(bufinf[buf.index].start)){ perror("mmap"); exit(1); } } for(i = 0; i < reqbuf.count; i++){ buf.index = i; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; ret = ::ioctl(fd, VIDIOC_QBUF, &buf); if(ret < 0){ perror("VIDIOC_QBUF"); exit(1); } } enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ret = ::ioctl(fd, VIDIOC_STREAMON, &type); if(ret < 0){ perror("VIDIOC_STREAMON"); exit(1); } return 0; } camera::camera(QWidget *parent) : QMainWindow(parent), ui(new Ui::camera) { char devname[32]; int i=0; int ret; struct v4l2_capability cap; ui->setupUi(this); while(i < 100) { sprintf(devname,"/dev/video%d",i++); fd = ::open(devname,O_RDWR); if(fd < 0) { continue; } ui->comboBox->addItem(QWidget::tr(devname)); ::close(fd); } } camera::~camera() { free(bufinf); ::close(fd); delete ui; } void camera::moveEvent(QMoveEvent *) { this->move(QPoint(0,0)); } void camera::resizeEvent(QResizeEvent *) { this->showMaximized(); } void camera::on_pushButton_2_clicked() { take_photo(); } static bool take = 0; void camera::show_() { int ret; unsigned char *rgb=new unsigned char [640 * 480 *3]; struct v4l2_buffer buf; fd_set readset; FD_ZERO(&readset); FD_SET(fd, &readset); ret = select(fd + 1, &readset, NULL, NULL, NULL); if(ret < 0){ perror("select"); exit(1); } buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; ret = ioctl(fd, VIDIOC_DQBUF, &buf); if(ret < 0){ perror("VIDIOC_DQBUF"); exit(1); } convert_yuv_to_rgb_buffer((unsigned char *)bufinf[buf.index].start,rgb,640,480); ret = ioctl(fd, VIDIOC_QBUF, &buf); if(ret < 0){ perror("VIDIOC_QBUF"); exit(1); } QImage *mage = new QImage(rgb,640,480,QImage::Format_RGB888); if (take == 1) { mage->save(tr("%1.jpg").arg("/mnt/Photo/Photo_2019.04.15/IMG" + QDate::currentDate().toString("yyyyMMdd") + QTime::currentTime().toString("hhmmss")),"JPG"); // mage->save(tr("%1.jpg").arg("/home/root/Photo/IMG" + QDate::currentDate().toString("yyyyMMdd") + QTime::currentTime().toString("hhmmss")),"JPG"); take = 0; } QImage resultimg=mage->scaled(ui->label->size(),Qt::KeepAspectRatio,Qt::SmoothTransformation); ui->label->setPixmap(QPixmap::fromImage(resultimg)); delete mage; delete rgb; } void camera::take_photo() { take = 1; } void camera::on_comboBox_activated(const QString &arg1) { QString text=ui->comboBox->currentText(); QByteArray devtext=text.toLatin1(); char *devname=devtext.data(); int ret; struct v4l2_capability cap; fd = ::open(devname, O_RDWR); if(fd < 0) { perror("open error"); } camera::camera_init(); QTimer *timer; timer=new QTimer(); timer->setInterval(10); connect(timer,SIGNAL(timeout()),this,SLOT(show_())); timer->start(10); camera_flag=1; } void camera::on_pushButton_clicked() { close(); } ``` # camera.h ``` #ifndef CAMERA_H #define CAMERA_H #include <QMainWindow> #include <QTimer> #include <QImage> #include <QPixmap> #include <QDebug> #include <QStringList> #include <QByteArray> #include <QComboBox> extern "C"{ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <sys/types.h> #include <fcntl.h> #include <sys/ioctl.h> #include <string.h> #include <time.h> #include <sys/select.h> #include <sys/time.h> #include <sys/types.h> #include <unistd.h> #include <jpeglib.h> #include <linux/videodev2.h> } namespace Ui { class camera; } struct bufinfor{ void *start; unsigned int length; }; class camera : public QMainWindow { Q_OBJECT public: explicit camera(QWidget *parent = 0); ~camera(); protected: void moveEvent(QMoveEvent *); void resizeEvent(QResizeEvent *); private slots: int camera_init(void); void on_pushButton_2_clicked(); void show_(); void take_photo(); void on_comboBox_activated(const QString &arg1); void on_pushButton_clicked(); private: Ui::camera *ui; int fd; int camera_flag; struct bufinfor *bufinf; }; #endif // CAMERA_H ``` usbcamera.pro ``` #------------------------------------------------- # # Project created by QtCreator 2019-08-02T09:08:26 # #------------------------------------------------- QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = usbcamera TEMPLATE = app LIBS += -L. -ljpeg SOURCES += main.cpp\ camera.cpp HEADERS += camera.h FORMS += camera.ui ``` 程序界面如下 ![图片说明](https://img-ask.csdn.net/upload/201908/16/1565962170_711562.jpg) ![图片说明](https://img-ask.csdn.net/upload/201908/16/1565962188_747692.jpg) 求助大神该怎么保存拍摄的视频 非常感谢

求一个把bmp图像灰度化并把灰度化后的像素存入数组里的C语言函数,不用opencv

求一个把bmp图像灰度化并把灰度化后的像素存入数组里的C语言函数,不用opencv

对图像进行锐化和模糊操作之后保存到桌面,保存的图片和显示的不一样

import java.awt.*; import java.awt.event.*; import java.awt.image.*; import javax.imageio.ImageIO; import javax.swing.*; import javax.swing.filechooser.FileSystemView; import java.io.*; import java.text.SimpleDateFormat; import java.util.*; /* * 图片编辑器 */ public class PicEdit extends JFrame { private int currentPixArray[] = null;// 保存当前操作的像素矩阵 BufferedImage bufImage = null; //用于显示的缓冲区图像 BufferedImage originalBufImage; //原始缓冲区图像 private String lastDir = "";// 图像的路径 private JLabel imageLabel = null;// 用于显示图像的标签 private BufferedImage newImage;// 加载的图像 private int h, w;// 图像的高和宽 private LinkedList<int[]> imageStack = new LinkedList<int[]>();// 保存历史操作图像矩阵 private LinkedList<int[]> tempImageStack = new LinkedList<int[]>(); public PicEdit() { super("图片特效工具"); // 创建菜单 JToolBar toolBar = new JToolBar(); this.add(toolBar,BorderLayout.NORTH); //skin sk = new skin(); JButton openbutton = new JButton(new ImageIcon("sk.getAddpic()")); //JButton exitbutton = new JButton(new ImageIcon("sk.getExit()")); //JButton graybutton = new JButton(new ImageIcon("sk.getGray()")); //JButton balancebutton = new JButton(new ImageIcon("sk.getBalance()")); JButton blurbutton = new JButton(new ImageIcon("sk.getBlur()")); JButton sharpenbutton = new JButton(new ImageIcon("sk.getSharpen()")); JButton resetbutton = new JButton(new ImageIcon("sk.getReset()")); JButton backbutton = new JButton(new ImageIcon("sk.getPrevious()")); JButton frontbutton = new JButton(new ImageIcon("sk.getNext()")); //JButton waterbutton = new JButton(new ImageIcon("sk.getWater()")); //JButton spotlightbutton = new JButton(new ImageIcon("sk.getSpotlight()")); //JButton bitbltbutton = new JButton(new ImageIcon("sk.getBiblt()")); //JButton printscbutton = new JButton(new ImageIcon("sk.getPrintsc()")); JButton savebutton = new JButton(new ImageIcon("sk.getSave()")); openbutton.setToolTipText("打开文件"); openbutton.setText("打开文件"); openbutton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);//让文字置于图标 openbutton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);//下方 openbutton.addActionListener(new OpenListener()); blurbutton.setToolTipText("模糊"); blurbutton.setText("模糊"); blurbutton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); blurbutton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); blurbutton.addActionListener(new BlurActionListener()); sharpenbutton.setToolTipText("锐化"); sharpenbutton.setText("锐化"); sharpenbutton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); sharpenbutton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); sharpenbutton.addActionListener(new SharpenActionListener()); resetbutton.setToolTipText("还原"); resetbutton.setText("还原"); resetbutton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); resetbutton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); resetbutton.addActionListener(new ResetMenuItemActionListener()); backbutton.setToolTipText("后退"); backbutton.setText("后退"); backbutton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); backbutton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); backbutton.addActionListener(new BackActionListener()); frontbutton.setToolTipText("前进"); frontbutton.setText("前进"); frontbutton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); frontbutton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); frontbutton.addActionListener(new FrontActionListener()); savebutton.setToolTipText("保存图片到桌面"); savebutton.setText("保存"); savebutton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); savebutton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); savebutton.addActionListener(new SaveListener()); toolBar.add(openbutton); toolBar.add(blurbutton); toolBar.add(sharpenbutton); toolBar.add(backbutton); toolBar.add(frontbutton); toolBar.add(resetbutton); toolBar.add(savebutton); this.setSize(1200,700); this.setLocation(20,20); this.setVisible(true); this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); imageLabel = new JLabel(""); JScrollPane pane = new JScrollPane(imageLabel); this.add(pane, BorderLayout.CENTER); this.setVisible(true); } //-----------------菜单监听器---------------// private class OpenListener implements ActionListener { public void actionPerformed(ActionEvent e) { FileDialog d = new FileDialog(PicEdit.this,"Open image file",FileDialog.LOAD); d.setFile(".jpg"); d.setDirectory(lastDir); d.setVisible(true); String file = d.getFile(); lastDir = d.getDirectory(); if(file!=null) { try { newImage = ImageIO.read(new File(lastDir+file)); originalBufImage = newImage; w = newImage.getWidth(); h = newImage.getHeight(); currentPixArray = getPixArray(newImage, w, h); imageStack.clear(); tempImageStack.clear(); imageStack.addLast(currentPixArray); imageLabel.setIcon(new ImageIcon(newImage)); } catch (IOException ex) { System.out.println(ex); } } PicEdit.this.repaint(); } } private class BackActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { if (imageStack.size() <= 1) { JOptionPane.showMessageDialog(null, "此幅图片的处理已经没有后退历史操作了", "提示", JOptionPane.INFORMATION_MESSAGE); } else { tempImageStack.addLast(imageStack.removeLast()); currentPixArray = imageStack.getLast(); showImage(currentPixArray); PicEdit.this.setRGB(newImage,0,0,w,h,currentPixArray);//将变换后的结果保存到newImage里 } } } private class FrontActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { if (tempImageStack.size() < 1) { JOptionPane.showMessageDialog(null, "此幅图片的处理已经没有前进历史操作了", "提示", JOptionPane.INFORMATION_MESSAGE); } else { currentPixArray = tempImageStack.removeFirst(); imageStack.addLast(currentPixArray); showImage(currentPixArray); PicEdit.this.setRGB(newImage,0,0,w,h,currentPixArray); } } } private class BlurActionListener implements ActionListener{ public void actionPerformed(ActionEvent e){ PicEdit.this.blur(); } } private class SharpenActionListener implements ActionListener{ public void actionPerformed(ActionEvent e){ PicEdit.this.sharpen(); } } private class ResetMenuItemActionListener implements ActionListener{ public void actionPerformed(ActionEvent e){ PicEdit.this.reset(); } } private class SaveListener implements ActionListener{ public void actionPerformed(ActionEvent e){ save(); } } //-----------------过滤图像---------------// public void applyFilter(float[] data) { if (newImage == null) return; //如果newImage为空则直接返回 Kernel kernel = new Kernel(3, 3, data); ConvolveOp imageOp=new ConvolveOp(kernel,ConvolveOp.EDGE_NO_OP, null); //创建卷积变换操作对象 BufferedImage filteredBufImage = new BufferedImage(newImage.getWidth(PicEdit.this),newImage.getHeight(PicEdit.this),BufferedImage.TYPE_INT_ARGB); //过滤后的缓冲区图像 imageOp.filter(newImage, filteredBufImage);//过滤图像,目标图像在filteredBufImage newImage = filteredBufImage; //让用于显示的缓冲区图像指向过滤后的图像 int[] resultArray = getPixArray(newImage, w, h); imageStack.addLast(resultArray); currentPixArray = resultArray; showImage(resultArray); tempImageStack.clear(); PicEdit.this.setRGB(newImage,0,0,w,h,resultArray); } //-----------------模糊图像---------------// public void blur() { if (newImage == null) return; float[] data = { 0.0625f, 0.125f, 0.0625f, 0.125f, 0.025f, 0.125f, 0.0625f, 0.125f, 0.0625f }; applyFilter(data); } //-----------------锐化图像---------------// public void sharpen() { if (newImage == null) return; float[] data = { -1.0f, -1.0f, -1.0f, -1.0f, 9.0f, -1.0f, -1.0f, -1.0f, -1.0f }; applyFilter(data); } //-----------------还原图像---------------// public void reset() { if (newImage == null) return; int[] resultArray = imageStack.getFirst(); imageStack.addLast(resultArray); currentPixArray = resultArray; showImage(resultArray); tempImageStack.clear(); PicEdit.this.setRGB(newImage,0,0,w,h,resultArray); } //-----------------获取图像像素矩阵---------------// private int[] getPixArray(Image im, int w, int h) { int[] pix = new int[w * h]; PixelGrabber pg = null; try { pg = new PixelGrabber(im, 0, 0, w, h, pix, 0, w); if (pg.grabPixels() != true) try { throw new java.awt.AWTException("pg error" + pg.status()); } catch (Exception eq) { eq.printStackTrace(); } } catch (Exception ex) { ex.printStackTrace(); } return pix; } //-----------------显示图片---------------// private void showImage(int[] srcPixArray) { Image pic = createImage(new MemoryImageSource(w, h, srcPixArray, 0, w)); ImageIcon ic = new ImageIcon(pic); imageLabel.setIcon(ic); imageLabel.repaint(); } //-----------------将图像数组转变成BufferedImage图像---------------// public void setRGB( BufferedImage image, int x, int y, int width, int height, int[] pixels ) { int type = image.getType(); if ( type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB ) image.getRaster().setDataElements( x, y, width, height, pixels ); else image.setRGB( x, y, width, height, pixels, 0, width ); } //-----------------保存图像到桌面---------------// public void save(){ SimpleDateFormat sdf = new SimpleDateFormat("yyyymmddHHmmss"); String name = sdf.format(new Date()); File path = FileSystemView.getFileSystemView().getHomeDirectory(); String format = "jpg"; File f = new File(path + File.separator + name + "." + format); try { ImageIO.write(newImage, format, f); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args){ new PicEdit(); } }

多个相机要如何统一坐标

大家好,请教下大家,我现在使用四个相机对两个产品进行对位,使两个产品重合在一起。方法是一个产品使用两个相机,每个相机拍一个mark点,那么我要怎么处理将这两个相机的 mark点联系起来,确定产品的位置,然后再跟另外两个相机的mark点做比较以便移动其中的一个产品,使两个产品重合呢? 是要将四个相机进行标定,将将它们的世界坐标统一到同一个坐标系中来吗?如果是要这样处理,那要怎么将各个相机的世界坐标统一成一个呢? 没有金币了,大家见谅~

android采用ffmpeg合成mp4不显示图像

commands[0] = "ffmpeg"; commands[1] = "-r";//桢速率(可以改,确认非标准桢率会导致音画不同步,所以只能设定为15或者29.97) commands[2] = "29.97"; commands[3] = "-f";//截取图片 格式 commands[4] = "image2"; commands[5] = "-i";//输入文件名 commands[6] = imageUrl; commands[7] = "-i"; commands[8] = musicUrl; commands[9] = "-pix_fmt";//查看支持图片格式 commands[10] = "yuvj420p"; commands[11] = "-t"; commands[12] = "930";//置纪录时间 hh:mm:ss[.xxx]格式的记录时间也支持 commands[13] = "-vcodec";//使用mpeg4压缩 commands[14] = "mpeg4"; commands[15] = outputUrls; ``` ``` 这样生成的mp4文件 在qq上进度条不走 在我项目使用的视频播放器 有时候会无法出现图像 黑屏 求大神解答

大学四年自学走来,这些私藏的实用工具/学习网站我贡献出来了

大学四年,看课本是不可能一直看课本的了,对于学习,特别是自学,善于搜索网上的一些资源来辅助,还是非常有必要的,下面我就把这几年私藏的各种资源,网站贡献出来给你们。主要有:电子书搜索、实用工具、在线视频学习网站、非视频学习网站、软件下载、面试/求职必备网站。 注意:文中提到的所有资源,文末我都给你整理好了,你们只管拿去,如果觉得不错,转发、分享就是最大的支持了。 一、电子书搜索 对于大部分程序员...

在中国程序员是青春饭吗?

今年,我也32了 ,为了不给大家误导,咨询了猎头、圈内好友,以及年过35岁的几位老程序员……舍了老脸去揭人家伤疤……希望能给大家以帮助,记得帮我点赞哦。 目录: 你以为的人生 一次又一次的伤害 猎头界的真相 如何应对互联网行业的「中年危机」 一、你以为的人生 刚入行时,拿着傲人的工资,想着好好干,以为我们的人生是这样的: 等真到了那一天,你会发现,你的人生很可能是这样的: ...

Java基础知识面试题(2020最新版)

文章目录Java概述何为编程什么是Javajdk1.5之后的三大版本JVM、JRE和JDK的关系什么是跨平台性?原理是什么Java语言有哪些特点什么是字节码?采用字节码的最大好处是什么什么是Java程序的主类?应用程序和小程序的主类有何不同?Java应用程序与小程序之间有那些差别?Java和C++的区别Oracle JDK 和 OpenJDK 的对比基础语法数据类型Java有哪些数据类型switc...

我以为我学懂了数据结构,直到看了这个导图才发现,我错了

数据结构与算法思维导图

技术大佬:我去,你写的 switch 语句也太老土了吧

昨天早上通过远程的方式 review 了两名新来同事的代码,大部分代码都写得很漂亮,严谨的同时注释也很到位,这令我非常满意。但当我看到他们当中有一个人写的 switch 语句时,还是忍不住破口大骂:“我擦,小王,你丫写的 switch 语句也太老土了吧!” 来看看小王写的代码吧,看完不要骂我装逼啊。 private static String createPlayer(PlayerTypes p...

和黑客斗争的 6 天!

互联网公司工作,很难避免不和黑客们打交道,我呆过的两家互联网公司,几乎每月每天每分钟都有黑客在公司网站上扫描。有的是寻找 Sql 注入的缺口,有的是寻找线上服务器可能存在的漏洞,大部分都...

Linux 会成为主流桌面操作系统吗?

整理 |屠敏出品 | CSDN(ID:CSDNnews)2020 年 1 月 14 日,微软正式停止了 Windows 7 系统的扩展支持,这意味着服役十年的 Windows 7,属于...

讲一个程序员如何副业月赚三万的真实故事

loonggg读完需要3分钟速读仅需 1 分钟大家好,我是你们的校长。我之前讲过,这年头,只要肯动脑,肯行动,程序员凭借自己的技术,赚钱的方式还是有很多种的。仅仅靠在公司出卖自己的劳动时...

学习总结之HTML5剑指前端(建议收藏,图文并茂)

前言学习《HTML5与CSS3权威指南》这本书很不错,学完之后我颇有感触,觉得web的世界开明了许多。这本书是需要有一定基础的web前端开发工程师。这本书主要学习HTML5和css3,看...

女程序员,为什么比男程序员少???

昨天看到一档综艺节目,讨论了两个话题:(1)中国学生的数学成绩,平均下来看,会比国外好?为什么?(2)男生的数学成绩,平均下来看,会比女生好?为什么?同时,我又联想到了一个技术圈经常讨...

搜狗输入法也在挑战国人的智商!

故事总是一个接着一个到来...上周写完《鲁大师已经彻底沦为一款垃圾流氓软件!》这篇文章之后,鲁大师的市场工作人员就找到了我,希望把这篇文章删除掉。经过一番沟通我先把这篇文章从公号中删除了...

副业收入是我做程序媛的3倍,工作外的B面人生是怎样的?

提到“程序员”,多数人脑海里首先想到的大约是:为人木讷、薪水超高、工作枯燥…… 然而,当离开工作岗位,撕去层层标签,脱下“程序员”这身外套,有的人生动又有趣,马上展现出了完全不同的A/B面人生! 不论是简单的爱好,还是正经的副业,他们都干得同样出色。偶尔,还能和程序员的特质结合,产生奇妙的“化学反应”。 @Charlotte:平日素颜示人,周末美妆博主 大家都以为程序媛也个个不修边幅,但我们也许...

MySQL数据库面试题(2020最新版)

文章目录数据库基础知识为什么要使用数据库什么是SQL?什么是MySQL?数据库三大范式是什么mysql有关权限的表都有哪几个MySQL的binlog有有几种录入格式?分别有什么区别?数据类型mysql有哪些数据类型引擎MySQL存储引擎MyISAM与InnoDB区别MyISAM索引与InnoDB索引的区别?InnoDB引擎的4大特性存储引擎选择索引什么是索引?索引有哪些优缺点?索引使用场景(重点)...

新一代神器STM32CubeMonitor介绍、下载、安装和使用教程

关注、星标公众号,不错过精彩内容作者:黄工公众号:strongerHuang最近ST官网悄悄新上线了一款比较强大的工具:STM32CubeMonitor V1.0.0。经过我研究和使用之...

记一次腾讯面试,我挂在了最熟悉不过的队列上……

腾讯后台面试,面试官问:如何自己实现队列?

如果你是老板,你会不会踢了这样的员工?

有个好朋友ZS,是技术总监,昨天问我:“有一个老下属,跟了我很多年,做事勤勤恳恳,主动性也很好。但随着公司的发展,他的进步速度,跟不上团队的步伐了,有点...

我入职阿里后,才知道原来简历这么写

私下里,有不少读者问我:“二哥,如何才能写出一份专业的技术简历呢?我总感觉自己写的简历太烂了,所以投了无数份,都石沉大海了。”说实话,我自己好多年没有写过简历了,但我认识的一个同行,他在阿里,给我说了一些他当年写简历的方法论,我感觉太牛逼了,实在是忍不住,就分享了出来,希望能够帮助到你。 01、简历的本质 作为简历的撰写者,你必须要搞清楚一点,简历的本质是什么,它就是为了来销售你的价值主张的。往深...

冒泡排序动画(基于python pygame实现)

本项目效果初始截图如下 动画见本人b站投稿:https://www.bilibili.com/video/av95491382 本项目对应github地址:https://github.com/BigShuang python版本:3.6,pygame版本:1.9.3。(python版本一致应该就没什么问题) 样例gif如下 ======================= 大爽歌作,mad

Redis核心原理与应用实践

Redis核心原理与应用实践 在很多场景下都会使用Redis,但是到了深层次的时候就了解的不是那么深刻,以至于在面试的时候经常会遇到卡壳的现象,学习知识要做到系统和深入,不要把Redis想象的过于复杂,和Mysql一样,是个读取数据的软件。 有一个理解是Redis是key value缓存服务器,更多的优点在于对value的操作更加丰富。 安装 yum install redis #yum安装 b...

现代的 “Hello, World”,可不仅仅是几行代码而已

作者 |Charles R. Martin译者 | 弯月,责编 | 夕颜头图 |付费下载自视觉中国出品 | CSDN(ID:CSDNnews)新手...

带了6个月的徒弟当了面试官,而身为高级工程师的我天天修Bug......

即将毕业的应届毕业生一枚,现在只拿到了两家offer,但最近听到一些消息,其中一个offer,我这个组据说客户很少,很有可能整组被裁掉。 想问大家: 如果我刚入职这个组就被裁了怎么办呢? 大家都是什么时候知道自己要被裁了的? 面试软技能指导: BQ/Project/Resume 试听内容: 除了刷题,还有哪些技能是拿到offer不可或缺的要素 如何提升面试软实力:简历, 行为面试,沟通能...

!大部分程序员只会写3年代码

如果世界上都是这种不思进取的软件公司,那别说大部分程序员只会写 3 年代码,恐怕就没有程序员这种职业。

离职半年了,老东家又发 offer,回不回?

有小伙伴问松哥这个问题,他在上海某公司,在离职了几个月后,前公司的领导联系到他,希望他能够返聘回去,他很纠结要不要回去? 俗话说好马不吃回头草,但是这个小伙伴既然感到纠结了,我觉得至少说明了两个问题:1.曾经的公司还不错;2.现在的日子也不是很如意。否则应该就不会纠结了。 老实说,松哥之前也有过类似的经历,今天就来和小伙伴们聊聊回头草到底吃不吃。 首先一个基本观点,就是离职了也没必要和老东家弄的苦...

2020阿里全球数学大赛:3万名高手、4道题、2天2夜未交卷

阿里巴巴全球数学竞赛( Alibaba Global Mathematics Competition)由马云发起,由中国科学技术协会、阿里巴巴基金会、阿里巴巴达摩院共同举办。大赛不设报名门槛,全世界爱好数学的人都可参与,不论是否出身数学专业、是否投身数学研究。 2020年阿里巴巴达摩院邀请北京大学、剑桥大学、浙江大学等高校的顶尖数学教师组建了出题组。中科院院士、美国艺术与科学院院士、北京国际数学...

为什么你不想学习?只想玩?人是如何一步一步废掉的

不知道是不是只有我这样子,还是你们也有过类似的经历。 上学的时候总有很多光辉历史,学年名列前茅,或者单科目大佬,但是虽然慢慢地长大了,你开始懈怠了,开始废掉了。。。 什么?你说不知道具体的情况是怎么样的? 我来告诉你: 你常常潜意识里或者心理觉得,自己真正的生活或者奋斗还没有开始。总是幻想着自己还拥有大把时间,还有无限的可能,自己还能逆风翻盘,只不是自己还没开始罢了,自己以后肯定会变得特别厉害...

HTTP与HTTPS的区别

面试官问HTTP与HTTPS的区别,我这样回答让他竖起大拇指!

程序员毕业去大公司好还是小公司好?

虽然大公司并不是人人都能进,但我仍建议还未毕业的同学,尽力地通过校招向大公司挤,但凡挤进去,你这一生会容易很多。 大公司哪里好?没能进大公司怎么办?答案都在这里了,记得帮我点赞哦。 目录: 技术氛围 内部晋升与跳槽 啥也没学会,公司倒闭了? 不同的人脉圈,注定会有不同的结果 没能去大厂怎么办? 一、技术氛围 纵观整个程序员技术领域,哪个在行业有所名气的大牛,不是在大厂? 而且众所...

男生更看重女生的身材脸蛋,还是思想?

往往,我们看不进去大段大段的逻辑。深刻的哲理,往往短而精悍,一阵见血。问:产品经理挺漂亮的,有点心动,但不知道合不合得来。男生更看重女生的身材脸蛋,还是...

程序员为什么千万不要瞎努力?

本文作者用对比非常鲜明的两个开发团队的故事,讲解了敏捷开发之道 —— 如果你的团队缺乏统一标准的环境,那么即使勤劳努力,不仅会极其耗时而且成果甚微,使用...

为什么程序员做外包会被瞧不起?

二哥,有个事想询问下您的意见,您觉得应届生值得去外包吗?公司虽然挺大的,中xx,但待遇感觉挺低,马上要报到,挺纠结的。

立即提问
相关内容推荐