Pose泰裤辣! 一键提取姿态生成新图像

摘要:从图像提取人体姿态,用姿态信息控制生成具有相同姿态的新图像。

本文分享自华为云社区《Pose泰裤辣! 一键提取姿态生成新图像》,作者: Emma_Liu 。

人体姿态骨架生成图像 ControlNet-Human Pose in Stable Diffusion

相关链接:Notebook案例地址: 人体姿态生成图像 ControlNet-Human Pose in Stable Diffusion
AI gallery:http://developer.huaweicloud.com/develop/aigallery/home.html
也可通过AI Gallery,搜索【人体姿态生成图像】一键体验!

ControlNet

什么是ControlNet?ControlNet最早是在L.Zhang等人的论文《Adding Conditional Control to Text-to-Image Diffusion Model》中提出的,目的是提高预训练的扩散模型的性能。它引入了一个框架,支持在扩散模型 (如 Stable Diffusion) 上附加额外的多种空间语义条件来控制生成过程。

ControlNet可以复制构图和人体姿势。它解决了生成想要的确切姿势困难的问题。

Human Pose使用OpenPose检测关键点,如头部、肩膀、手的位置等。它适用于复制人类姿势,但不适用于其他细节,如服装、发型和背景。

ControlNet 的工作原理是将可训练的网络模块附加到稳定扩散模型的U-Net (噪声预测器)的各个部分。Stable Diffusion 模型的权重是锁定的,在训练过程中它们是不变的。在训练期间仅修改附加模块。

研究论文中的模型图很好地总结了这一点。最初,附加网络模块的权重全部为零,使新模型能够利用经过训练和锁定的模型。

训练 ControlNet 包括以下步骤:

  1. 克隆扩散模型的预训练参数,如Stable Diffusion的潜在UNet,(称为 “可训练副本”),同时也单独保留预训练的参数(“锁定副本”)。这样做是为了使锁定的参数副本能够保留从大型数据集中学习到的大量知识,而可训练的副本则用于学习特定的任务方面。
  2. 参数的可训练副本和锁定副本通过 "零卷积 "层连接,该层作为ControlNet框架的一部分被优化。这是一个训练技巧,在训练新的条件时,保留冻结模型已经学会的语义。

从图上看,训练ControlNet是这样的:

ControlNet提供了八个扩展,每个扩展都可以对扩散模型进行不同的控制。这些扩展是Canny, Depth, HED, M-LSD, Normal, Openpose, Scribble, and Semantic Segmentation。

ControlNet-Pose2imge适配ModelArts

使用方法:

输入一个图像,并提示模型生成一个图像。Openpose将为你检测姿势,从图像提取人体姿态,用姿态信息控制生成具有相同姿态的新图像。

对两张图像分别为进行人体骨骼姿态提取,然后根据输入描述词生成图像,如下图所示:

本案例需使用Pytorch-1.8 GPU-P100及以上规格运行

点击Run in ModelArts,将会进入到ModelArts CodeLab中,这时需要你登录华为云账号,如果没有账号,则需要注册一个,且要进行实名认证,参考《ModelArts准备工作_简易版》 即可完成账号注册和实名认证。 登录之后,等待片刻,即可进入到CodeLab的运行环境

1. 环境准备

为了方便用户下载使用及快速体验,本案例已将代码及control_sd15_openpose预训练模型转存至华为云OBS中。注意:为了使用该模型与权重,你必须接受该模型所要求的License,请访问huggingface的lllyasviel/ControlNet, 仔细阅读里面的License。模型下载与加载需要几分钟时间。

import os
import moxing as mox
parent = os.path.join(os.getcwd(),'ControlNet')
if not os.path.exists(parent):
 mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/ControlNet/ControlNet',parent)
 if os.path.exists(parent):
 print('Code Copy Completed.')
 else:
 raise Exception('Failed to Copy the Code.')
else:
 print("Code already exists!")
pose_model_path = os.path.join(os.getcwd(),"ControlNet/models/control_sd15_openpose.pth")
body_model_path = os.path.join(os.getcwd(),"ControlNet/annotator/ckpts/body_pose_model.pth")
hand_model_path = os.path.join(os.getcwd(),"ControlNet/annotator/ckpts/hand_pose_model.pth")
if not os.path.exists(pose_model_path):
 mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/ControlNet/ControlNet_models/control_sd15_openpose.pth',pose_model_path)
 mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/ControlNet/ControlNet_models/body_pose_model.pth',body_model_path)
 mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/ControlNet/ControlNet_models/hand_pose_model.pth',hand_model_path)
 if os.path.exists(pose_model_path):
 print('Models Download Completed')
 else:
 raise Exception('Failed to Copy the Models.')
else:
 print("Model Packages already exists!")

check GPU & 安装依赖

大约耗时1min

!nvidia-smi
%cd ControlNet
!pip uninstall torch torchtext -y
!pip install torch==1.12.1 torchvision==0.13.1 torchaudio==0.12.1 
!pip install omegaconf==2.1.1 einops==0.3.0
!pip install pytorch-lightning==1.5.0
!pip install transformers==4.19.2 open_clip_torch==2.0.2
!pip install gradio==3.24.1
!pip install translate==3.6.1
!pip install scikit-image==0.19.3
!pip install basicsr==1.4.2

导包

import config
import cv2
import einops
import gradio as gr
import numpy as np
import torch
import random
from pytorch_lightning import seed_everything
from annotator.util import resize_image, HWC3
from annotator.openpose import OpenposeDetector
from cldm.model import create_model, load_state_dict
from cldm.ddim_hacked import DDIMSampler
from translate import Translator
from PIL import Image
import matplotlib.pyplot as plt

2. 加载模型

apply_openpose = OpenposeDetector()
model = create_model('./models/cldm_v15.yaml').cpu()
model.load_state_dict(load_state_dict('./models/control_sd15_openpose.pth', location='cuda'))
model = model.cuda()
ddim_sampler = DDIMSampler(model)

3. 人体姿态生成图像

def infer(input_image, prompt, a_prompt, n_prompt, num_samples, image_resolution, detect_resolution, ddim_steps, guess_mode, strength, scale, seed, eta):
    trans = Translator(from_lang="ZH",to_lang="EN-US")
    prompt = trans.translate(prompt)
 a_prompt = trans.translate(a_prompt)
 n_prompt = trans.translate(n_prompt)
 # 图像预处理
 with torch.no_grad():
 if type(input_image) is str:
 input_image = np.array(Image.open(input_image))
 input_image = HWC3(input_image)
 detected_map, _ = apply_openpose(resize_image(input_image, detect_resolution))
 detected_map = HWC3(detected_map)
 img = resize_image(input_image, image_resolution)
        H, W, C = img.shape
 # 初始化检测映射
 detected_map = cv2.resize(detected_map, (W, H), interpolation=cv2.INTER_NEAREST)
        control = torch.from_numpy(detected_map.copy()).float().cuda() / 255.0
        control = torch.stack([control for _ in range(num_samples)], dim=0)
        control = einops.rearrange(control, 'b h w c -> b c h w').clone()
 # 设置随机种子
 if seed == -1:
            seed = random.randint(0, 65535)
 seed_everything(seed)
 if config.save_memory:
 model.low_vram_shift(is_diffusing=False)
 cond = {"c_concat": [control], "c_crossattn": [model.get_learned_conditioning([prompt + ', ' + a_prompt] * num_samples)]}
 un_cond = {"c_concat": None if guess_mode else [control], "c_crossattn": [model.get_learned_conditioning([n_prompt] * num_samples)]}
        shape = (4, H // 8, W // 8)
 if config.save_memory:
 model.low_vram_shift(is_diffusing=True)
 # 采样
 model.control_scales = [strength * (0.825 ** float(12 - i)) for i in range(13)] if guess_mode else ([strength] * 13) # Magic number. IDK why. Perhaps because 0.825**12<0.01 but 0.826**12>0.01
        samples, intermediates = ddim_sampler.sample(ddim_steps, num_samples,
                                                     shape, cond, verbose=False, eta=eta,
 unconditional_guidance_scale=scale,
 unconditional_conditioning=un_cond)
 if config.save_memory:
 model.low_vram_shift(is_diffusing=False)
 # 后处理
 x_samples = model.decode_first_stage(samples)
 x_samples = (einops.rearrange(x_samples, 'b c h w -> b h w c') * 127.5 + 127.5).cpu().numpy().clip(0, 255).astype(np.uint8)
        results = [x_samples[i] for i in range(num_samples)]
 return [detected_map] + results

设置参数,生成图像

上传您的图像至./ControlNet/test_imgs/ 路径下,然后更改图像路径及其他参数后,点击运行。

参数说明:

img_path:输入图像路径,黑白稿

prompt:提示词

a_prompt:次要的提示

n_prompt: 负面提示,不想要的内容

image_resolution: 对输入的图片进行最长边等比resize

detect_resolution: 中间生成条件图像的分辨率

scale:文本提示的控制强度,越大越强

guess_mode: 盲猜模式,默认关闭,开启后生成图像将不受prompt影响,使用更多样性的结果,生成后得到不那么遵守图像条件的结果

seed: 随机种子

ddim_steps: 采样步数,一般15-30,值越大越精细,耗时越长

DDIM eta: 生成过程中的随机噪声系数,一般选0或1,1表示有噪声更多样,0表示无噪声,更遵守描述条件

strength: 这是应用 ControlNet 的步骤数。它类似于图像到图像中的去噪强度。如果指导强度为 1,则 ControlNet 应用于 100% 的采样步骤。如果引导强度为 0.7 并且您正在执行 50 个步骤,则 ControlNet 将应用于前 70% 的采样步骤,即前 35 个步骤。

#@title ControlNet-OpenPose 
img_path = "test_imgs/pose1.png" #@param {type:"string"}
prompt = "优雅的女士" #@param {type:"string"}
seed = 1685862398 #@param {type:"slider", min:-1, max:2147483647, step:1}
guess_mode = False #@param {type:"raw", dropdown}
a_prompt = '质量最好,非常详细'
n_prompt = '长体,下肢,解剖不好,手不好,手指缺失,手指多,手指少,裁剪,质量最差,质量低'
num_samples = 1
image_resolution = 512
detect_resolution = 512
ddim_steps = 20
strength = 1.0
scale = 9.0
eta = 0.0
np_imgs = infer(img_path, prompt, a_prompt, n_prompt, num_samples, image_resolution, detect_resolution, ddim_steps, guess_mode, strength, scale, seed, eta)
ori = Image.open(img_path)
src = Image.fromarray(np_imgs[0])
dst = Image.fromarray(np_imgs[1])
fig = plt.figure(figsize=(25, 10))
ax1 = fig.add_subplot(1, 3, 1)
plt.title('Orginal image', fontsize=16)
ax1.axis('off')
ax1.imshow(ori)
ax2 = fig.add_subplot(1, 3, 2)
plt.title('Pose image', fontsize=16)
ax2.axis('off')
ax2.imshow(src)
ax3 = fig.add_subplot(1, 3, 3)
plt.title('Generate image', fontsize=16)
ax3.axis('off')
ax3.imshow(dst)
plt.show()

4. Gradio可视化部署

Gradio应用启动后可在下方页面上传图片根据提示生成图像,您也可以分享public url在手机端,PC端进行访问生成图像。

请注意: 在图像生成需要消耗显存,您可以在左侧操作栏查看您的实时资源使用情况,点击GPU显存使用率即可查看,当显存不足时,您生成图像可能会报错,此时,您可以通过重启kernel的方式重置,然后重头运行即可规避。

block = gr.Blocks().queue()
with block:
 with gr.Row():
 gr.Markdown("##  人体姿态生成图像")
 with gr.Row():
 with gr.Column():
 gr.Markdown("请上传一张人像图,设置好参数后,点击Run")
 input_image = gr.Image(source='upload', type="numpy")
            prompt = gr.Textbox(label="描述")
 run_button = gr.Button(label="Run")
 with gr.Accordion("高级选项", open=False):
 num_samples = gr.Slider(label="Images", minimum=1, maximum=3, value=1, step=1)
 image_resolution = gr.Slider(label="Image Resolution", minimum=256, maximum=768, value=512, step=64)
                strength = gr.Slider(label="Control Strength", minimum=0.0, maximum=2.0, value=1.0, step=0.01)
 guess_mode = gr.Checkbox(label='Guess Mode', value=False)
 detect_resolution = gr.Slider(label="OpenPose Resolution", minimum=128, maximum=1024, value=512, step=1)
 ddim_steps = gr.Slider(label="Steps", minimum=1, maximum=30, value=20, step=1)
                scale = gr.Slider(label="Guidance Scale", minimum=0.1, maximum=30.0, value=9.0, step=0.1)
                seed = gr.Slider(label="Seed", minimum=-1, maximum=2147483647, step=1, randomize=True)
                eta = gr.Number(label="eta (DDIM)", value=0.0)
 a_prompt = gr.Textbox(label="Added Prompt", value='best quality, extremely detailed')
 n_prompt = gr.Textbox(label="Negative Prompt",
                                      value='longbody, lowres, bad anatomy, bad hands, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality')
 with gr.Column():
 result_gallery = gr.Gallery(label='Output', show_label=False, elem_id="gallery").style(grid=2, height='auto')
 ips = [input_image, prompt, a_prompt, n_prompt, num_samples, image_resolution, detect_resolution, ddim_steps, guess_mode, strength, scale, seed, eta]
 run_button.click(fn=infer, inputs=ips, outputs=[result_gallery])
block.launch(share=True)

 

点击关注,第一时间了解华为云新鲜技术~

本文转载于网络 如有侵权请联系删除

相关文章

  • Markdown 拓展 - 对数学公式的支持

    MathJax和LaTeX数学公式支持MathJax是一款运行在浏览器中的开源数学符号渲染引擎,使用MathJax可以方便的在浏览器中显示数学公式,不需要使用图片。目前,MathJax可以解析Latex、MathML和ASCIIMathML的标记语言。MathJax项目于2009年开始,发起人有AmericanMathematicalSociety,DesignScience等,还有众多的支持者,个人感觉MathJax会成为今后数学符号渲染引擎中的主流,也许现在已经是了。本文接下来会讲述MathJax的基础用法,但不涉及MathJax的安装及配置。另外这里有个LaTeX教程,图文并茂,强烈建议参考收藏。它和MathJax有差异,但是很多语法可以通用。YoucanrenderLaTeXmathematicalexpressionsusingKaTeX实例特殊字符圆周率\pi复制加减乘除\times\div\pm\mp复制上下标这两种方法都可以 x_i^2 x^2_i复制只有上标的情况x^{10}复制括号小括号与方括号:使用原始的(),[]即可大括号:由于大括号{}被用来分组,因此需要使

  • MySQL按天,按周,按月,按时间段统计【转载】

    自己做过MySQL按天,按周,按月,按时间段统计,但是不怎么满意,后来找到这位大神的博客,转载一下,谢谢这位博主的分享知识点:DATE_FORMAT使用示例selectDATE_FORMAT(create_time, ‘%Y%m%d’)days,count(caseid)countfromtc_casegroupbydays; selectDATE_FORMAT(create_time, ‘%Y%u’)weeks,count(caseid)countfromtc_casegroupbyweeks; selectDATE_FORMAT(create_time, ‘%Y%m’)months,count(caseid)countfromtc_casegroupbymonths;DATE_FORMAT(date,format) 根据format字符串格式化date值。下列修饰符可以被用在format字符串中:%M月名字(January……December)%W星期名字(Sunday……Saturday)%D有英语前缀的月份的日期(1st,2nd,3rd,等等。)%Y年,数字,4位%y年,数

  • 一篇文章带你了解Java构造方法的定义和重载

    前面几篇文章用Java带大家一起了解了几个游戏小项目,感兴趣的小伙伴可以点击文章观摩下,手把手教你用Java打造一款简单故事书(上篇)、手把手教你用Java打造一款简单故事书(下篇)、手把手教你用Java打造一款简单考试系统(上篇)、手把手教你用Java打造一款简单考试系统(下篇)、手把手带你用Java打造一款对对碰游戏(上篇)、手把手带你用Java打造一款对对碰游戏(下篇)、手把手带你用Java实现点灯游戏(上篇)、手把手带你用Java实现点灯游戏(下篇),接下来的几篇文章是关于Java基础的,希望对大家的学习有帮助,欢迎大家在讨论区留言。一、构造方法的定义(一)什么构造方法实例化一个类的对象后,如果要给属性赋值,需要通过访问对象的属性或setXXX()方法。在实例化对象后同时给对象的属性赋值可以使用构造方法,构造方法也叫做构造函数。用来对对象进行初始化。(二)构造方法特点1.构造方法的名字必须和类名完全相同。2.方法名前面没有返回值,甚至连表示没有返回值的空类型(void)也没有。3.在方法中不能使用return语句返回一个值。4.构造方法一般定义是为public。5.使用new运

  • Android MenuItem 自定义长按事件的实现

    会出现一个Toast来提示Menu的名字,比如下图的更多。有的时候我们不需要这个Toast,或者说长按MenuItem的时候需要做一些其他的事情,该怎么办呢?实现过程首先我们先获取该MenuItem的View:Viewmenu_more=findViewById(R.id.menu_more);复制然后给它设置一个长按监听器:menu_more.setOnLongClickListener(newView.OnLongClickListener(){ @Override publicbooleanonLongClick(Viewv){ //TODO:Implementthismethod returntrue; } });复制在这个监听器中什么也不做,你会发现,长按MenuItem的Toast消失了!这时,长按还会有一个短振动,如果不需要振动,可以更改上方代码中returntrue;为returnfalse;就可以了。当然,如果你有别的需求,都可以在监听器中实现。注意事项获取MenuItem的View需要在Menu创建之后才能获取,因此我们不能把代码写在onCreate()方法中,需要

  • vue vuetify 实现智能联想

    使用Vuetify中的v-menu组件实现,控制光标焦点,在输入框获取的焦点时弹出联想词汇菜单,支持上下按键选中内容,菜单位置,样式按需调整即可数据获取方面通过监听输入框内容变化,调用对应接口获取数据注意如果产品功能要求极高的性能,要加防抖和节流处理<template> <divv-on:keyup.enter="search"> <v-menuoffset-y> <templatev-slot:activator="{on}"> <v-text-field solo hide-details label="请输入关键词" append-icon="search" v-model="text" class="input-search" autocomplete="off" v-on="on" ref="search" ></v-text-fie

  • 简单缓冲区溢出原理

    本篇原创作者:Rj45背景什么是缓冲区溢出?这里我借某台栈溢出靶机里面的第一道题目来解释缓冲区溢出的原理。可以看到靶机里面有两份权限不同的文件,而我目前拿到的shell是level0审计levelOne.c#include<stdio.h> #include<string.h> #include<unistd.h> intmain(intargc,char**argv){ uid_tuid=geteuid(); setresuid(uid,uid,uid); longkey=0x12345678; charbuf[32]; strcpy(buf,argv[1]); printf("Bufis:%s\n",buf); printf("Keyis:0x%08x\n",key); if(key==0x42424242){ execve("/bin/sh",0,0); } else{ printf("%s\n","Sorrytryagain..."); }

  • jquery对div元素进行鼠标移动(稍稍修改下可以实现div跟随鼠标)

    /* 网上找了资料都是对于event.clientX和offset().left进行了计算,但是去掉了这个计算方式,直接使用当前坐标也一样,效果都一样不太好 strHeader:标题jquery定位字符串 strForm:窗体jquery定位字符串 */ varisMove=false; //varx=0; //vary=0; //varoffx=0; //varoffy=0; functionmovePage(strHeader,strForm){ $(strHeader).mousedown( function(event){ isMove=true; //x=event.clientX; //y=event.clientY; //offx=$(strForm).offset().left; //offy=$(strForm).offset().top; } ); $(document).mousemove( function(event){ if(isMove){ $(strForm).css({ //'left':(event.clientX-(x-offx

  • 3-SII--Android的SD卡文件读写

    零、前言[1]读写SD卡需要运行时权限。 [2]如果对运行时权限不清楚的童鞋,可以看一下我的封装:TI--安卓运行时权限完美封装 一、使用:SD卡文件读写FileHelperfileHelper=FileHelper.get(); //在SD卡追加模式创建:data/writeFile2SD.txt文件,写入"toly" fileHelper.writeFile2SD("data/writeFile2SD.txt","toly",true); //在SD卡上创建一个空文件 fileHelper.createFile("create/create.txt"); //读取data/writeFile2SD.txt文件 Stringread=fileHelper.readFromSD("data/writeFile2SD.txt"); System.out.println(read);//tolytolytolytolytolytoly复制二、创建文件判断是否存在SD卡/** *判断是否存在

  • 融合之下的想象:影视众筹的未来在哪?

    作为众筹领域较具亮点的部分,影视众筹始终都是很多创业者关注的一个方面。除了创业者之外,具备了影视行业相关资源的传统公司同样将目光聚焦于此。创业者的关注与“互联网+”时代的到来有关,他们主要看中的是互联网对于传统行业的改造能力,期望通过互联网介入其中,找到新的发展可能;传统影视公司的关注与他们想要找到新的出口有关,他们希望通过影视众筹找到破解传统发展路径难题的方法,为未来发展提供新的动力。 虽然新型创业者与传统影视公司介入影视领域的初衷不同,但他们选择“资金”这个困扰影视行业的最大痛点切入却有异曲同工之处。无论是在互联网环境下,还是在传统环境下,困扰影视行业从业者的最大难题始终都是资金。传统模式下,影视从业者筹集资金的主要方式主要是以大型机构、影视投资公司等专业型的资本运作方式为主,这种资本运作方式能够惠及到的人群主要以知名导演和影视行业专业人士为主。随着互联网影响的加剧,影视行业的传播媒介和受众群体同样在发生着深刻变化。网络大电影、网络电视剧、网络短视频……这些基于互联网的新生事物在改变人们观看习惯的同时,同样衍生了全新的内容生产群体。传统的影视内容生产者们还无暇顾及网络衍生影视产品,

  • EM算法

    推导EM算法之前,先引用《统计学习方法》中EM算法的例子:例1.(三硬币模型)假设有3枚硬币,分别记作A,B,C。这些硬币正面出现的概率分别为π,p和q。投币实验如下,先投A,如果A是正面,即A=1,那么选择投B;A=0,投C。最后,如果B或者C是正面,那么y=1;是反面,那么y=0;独立重复n次试验(n=10),观测结果如下:1,1,0,1,0,0,1,0,1,1假设只能观测到投掷硬币的结果,不能观测投掷硬币的过程。问如何估计三硬币正面出现的概率,即π,p和q的值。解:设随机变量y是观测变量,则投掷一次的概率模型为:有n次观测数据Y,那么观测数据Y的似然函数为:那么利用最大似然估计求解模型解,即: 这里将概率模型公式和似然函数代入(1)式中,可以很轻松地推出(1)=>(2)=>(3),然后选取θ(π,p,q),使得(3)式值最大,即最大似然。然后,我们会发现因为(3)中右边多项式+符号的存在,使得(3)直接求偏导等于0或者用梯度下降法都很难求得θ值。这部分的难点是因为(3)多项式中+符号的存在,而这是因为这个三硬币模型中,我们无法得知最后得结果是硬币B还是硬币C抛出的这个

  • unity怎么创建球体_每天分享的小知识点

    大家好,又见面了,我是你们的朋友全栈君。Unity小科普老规矩,先介绍一下Unity的科普小知识:Unity是实时3D互动内容创作和运营平台。包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者,借助Unity将创意变成现实。Unity平台提供一整套完善的软件解决方案,可用于创作、运营和变现任何实时互动的2D和3D内容,支持平台包括手机、平板电脑、PC、游戏主机、增强现实和虚拟现实设备。也可以简单把Unity理解为一个游戏引擎,可以用来专业制作游戏!Unity踩坑小知识点学习在编辑器中绘制正方体虚线、球体虚线(Gizmos辅助线框)使用Gizmos类可以让我们在Unity中实现一种辅助线框,下面举例几种常用的线框。更多的API可以来官方手册关于Gizmos查看使用Gizmos绘制线框要在下面两个函数中使用:privatevoidOnDrawGizmos() { Debug.Log("持续调用"); } privatevoidOnDrawGizmosSelected() { Debug.Log("selected,只有物体选中后调用");

  • 如何找到nginx安装目录?

    尝试用 whereisnginx 返回了 nginx:/usr/lib64/nginx/etc/nginx/usr/local/sbin/nginx/usr/share/nginx 复制 这几个目录下都没有nginx。。。如何找?   正常安装的化whereis不应该找不到啊…… 或者你可以试试通过其他方式查找。 如果是通过apt/yum这些包管理器安装的,只需要: whichnginx复制 如果是自己编译的或者其他安装方式,一种办法是通过进程标识符找。如果nginx进程正在运行着,你可以先找到它的pid,然后再去proc里找: ps-aux|grepnginx #假如得到的pid是10086,那么就再执行 ls-l/proc/10086/exe复制 打印结果里就有程序的启动路径,一般而言就是安装路径了。 另一种方式是通过系统服务找。比如你可能会用systemd来管理系统服务,那么它的配置文件里就会记录程序的启动路径。 cat/usr/lib/systemd/system/nginx.service#假如你的配置文件在此路径下复制   showtoo

  • 位运算及其应用实例(1)

    位运算及其应用实例(1) 摘要 位运算是C/C++中的基本运算之一,即便是这样,它对大多数程序员来说是一个比较陌生的运算——大多数程序员很少使用位运算。本篇先简要介绍基本的位运算操作符及其用法(何时使用),然后介绍位运算符的几个典型应用: (1)      三种不用临时变量交换两个整数的实例,并分析每个实例的优缺点 (2)      进制转换,通过位运算实现将十进制数按二进制和十六进制输出,并得出一个通用的,用于将十进制按照2的n次方进制输出的程序。 (3)      给出利用位运算实现的计算整数的二进制表示中有多少个1的实例。 揭开位运算的面纱 所有数据在计算机底层都是按二进制存储的,一个数据可以看做是一个有序的位集合。每一位只有两种状态:0或1。位运算允许程序员操作数据的某一特定位,比如将某位设置为1(或0),查询某位的状态(1,或0)。位运算由位运算操作符和操作数组成,不同的位运算操作符定义了不同的位运

  • MySQL04:规范数据库设计

    为什么需要设计 当数据库比较复杂的时候,就需要设计了 糟糕的数据库设计 数据冗余,浪费空间 数据库的插入和删除很麻烦 程序的性能差 使用物理外键 良好的数据库设计 节省内存空间 保证数据库的完整性 方便系统的开发 设计数据库的步骤(个人博客): 收集信息,分析需求 用户表(用户登录注销,个人信息,写博客,创建分类) 分类表(文章分类,创建者) 文章表(文章信息) 评论表(评论) 关注数(关注数,粉丝数) 友情链接(其他链接) 标识实体(把需求落实到每个表和字段) user(id、username、password、gender、age) category(id、category_name、creator_id) article(id、title、author_id、category_id、content、create_time、update_time) comment(id、blog_id、user-id、content、create_time、user_id_parent) user_follow(id、user_id、follow_id) links(id

  • RemoteFX vGPU的尴尬现状和解决方案

    RemoteFXvGPU曾经是一个非常先进的GPU虚拟化和远程体验增强工具。然而在Windows1709版本后,RemoteFX就已经成了一个“abandonware”,由于过于老旧(最早面世于2010),已经很难和现在的新系统组件良好兼容。在Windows101809版本里,他们砍掉了通过GUI新增RemoteFXvGPU的路径,并提示了用户该技术不再受到支持。在之后微软正式宣布了RemoteFX的退位,并表示新的接替技术正在开发中,推荐用户使用 DiscreteDeviceAssignment 即分离设备指定方案替代。 然而问题是: 只有WindowsServer开放支持DDA,而WindowsPro/Workstation版本则都不能用。而且我觉得连Workstation版都不给,实在是有点让人无语。 DDA的启用非常麻烦,而且启用后客户机会独占该设备,宿主就没法使用了。 DDA和RemoteFX是两种不同的技术路径,适合的情景其实不完全一样,不能等价互相代替。 而我们熟悉的RemoteFX虽然有诸多缺陷,可日常使用还是很方便(特别是高分屏下流畅度会比纯C

  • 云管理软件ManageIQ管理Openstack和VMware的实验

    前言 ManageIQ早期(2006年4月-2012年11月)由公司维护,为闭源软件,2012年12月RedHat公司以1.04亿美元收购该公司,此后由RedHat维护。2014年6月开放了该软件的全部源代码。ManageIQ使用Ruby语言开发,WEB采用RubyOnRails框架搭建。默认使用PostgreSQL数据库。 ManageIQ 社区旨在提供工业领域先进的开源云管理平台,提供先进的管理和自动化功能。红帽深深相信社区动力创新和长期致力于这些开源技术将会获得不一样的收获,正如 ManageIQ 项目,目前是服务于红帽的 CLoudForms 开源混合云管理产品。红帽将会继续为开源社区做出重大贡献,旨在通过开源创新来推动云管理平台的发展。而现在,红帽也兑现了当初开源的诺言,发布了 ManageIQ 首个开源版本。 ManageIQ 社区里面有开发者,服务提供商,系统集成商,研究人员和用户,他们一起合作推动 OpenStack 和开源混合云的管理和发展。ManageIQ 

  • 转行自学编程经历回顾

    ?点  Stephen 关注我    今天2019年9月22日,对于平凡而普通的我来说是个特殊而不普通的日子。熟悉我的盆友都知道:我是毕业工作之后转行自学Java编程入行的。5年了,没错!今天是我成为程序员五周年的纪念日。(这里我要停顿三十秒,想象此时此刻有鲜花、彩蛋、还有掌声……然后我的丑脸就泛起了微笑)李笑来老师说过:我们相信通过学习获得重生——对我们来说,七年就是一辈子。七年一辈子!那,五年真的太漫长了。我试着一年一年往前回忆,遥想到了当初和当年。1、程序员之前的工作之前的自我介绍里有提过,我是应用电子技术专业毕业的大专生,经历了工厂流水线维修工、商场营业员、便利店督导等工作,毕业三年后自学java入行的。在成为一名程序员之前,我是一名深圳本地某品牌便利店区域督导,要负责近30家店的相关工作,公司规定每个星期每家店都得去一次,也就是说一个星期得跑完这30家店,一天得跑五六家店。2、家人的指引、支持就在我每天过着跑来跑去的生活时,我哥研究生毕业校招在华为写代码半年多了,觉得编程没有那么难,对我这个弟弟有想法了,开始鼓动我去培训学习

  • maven工程servlet实例之指定web资源包以及导入项目依赖的jar包以及jar包冲突解决

    maven工程servlet实例之指定web资源包     在webapp包下可以直接创建jsp文件,但是在java包下我们不可以直接创建jsp文件。      如果想要在java包下创建jsp文件,就需要设置:                  可以看到在java包那里出现了和webapp包一样的小蓝点 如果想要删除: 选中要删除的包,点击“-”号                 maven工程servlet实例之导入项目依赖的jar包 选择pom.xml        添加jar包        创建servlet 跳转到hello.jsp页面 publicclassMyServletextendsHttpServlet{ protectedvoiddoPost(Http

  • BZOJ3112 [ZJOI2013]防守战线

    Description 战线可以看作一个长度为n的序列,现在需要在这个序列上建塔来防守敌兵,在序列第i号位置上建一座塔有Ci的花费,且一个位置可以建任意多的塔费用累加计算。有m个区间[L1,R1],[L2,R2],…,[Lm,Rm],在第i个区间的范围内要建至少Di座塔。求最少花费。 Input 第一行为两个数n,m。 接下来一行,有n个数,描述C数组。 接下来m行,每行三个数Li,Ri,Di,描述一个区间。 Output 仅包含一行,一个数,为最少花费。 SampleInput 53 15634 231 154 352 SampleOutput 11 Hint 样例提示: 位置1建2个塔,位置3建一个塔,位置4建一个塔。花费1*2+6+3=11。 数据范围: 对于20%的数据,n≤20,m≤20。 对于50%的数据(包括上部分的数据),Di全部为1。 对于70%的数据(包括上部分的数据),n≤10

  • 2020牛客暑期多校训练营(第四场) C - Count New String (字符串,广义后缀自动机,序列自动机)

    CountNewString 题意: 定义字符串函数\(f(S,x,y)(1\lex\ley\len)\),返回一个长度为y-x+1的字符串,第i位是\(max_{i=x...x+k-1}S_i\) 设集合\(A={f(f(S,x_1,y_1),x_2-x_1+1,y_2-x_1+1)|1\lex_1\lex_2\ley_2\ley_2\len}\) 求集合A的大小 \(N\le1e5\)字符集大小<=10 分析: 先放出官方题解 方法一 核心点1比较容易想到,进一步可以观察到他们之间有很大一部分后面是重复的,感性的想到如果倒着插入Trie树,在Trie树上面的节点可能不会很多。具体证明来讲,当前字符\(i\),最近的大于它的字符的位置是\(j(j>i)\),那么在将位置\(i+1\)的字符插入到Trie树之后,还要把长度\((j-i)\)的字符串插入到Trie树中。考虑一个\(j_2\),再找一个最大的\(j_1\)有\(S_{j_1}\geS_{j_2}\),那么\([j_1,j_2]\)这个区间最多利用10次,所以Trie树节点不超过10N。然后就是常规的在Tr

  • 数独个人项目

    一、Github项目地址    https://github.com/wdfcode/sudoku 二、PSP表格 PSP2.1PersonalSoftwareProcessStages预估耗时(分钟)实际耗时(分钟) Planning 计划 50 60 ·Estimate ·估计这个任务需要多少时间 30 30 Development 开发 1220 1540 ·Analysis ·需求分析(包括学习新技术) 120 240 ·DesignSpec ·生成设计文档 30 40 ·DesignReview ·设计复审(和同事审核设计文档) 60 120 ·CodingStandard ·代码规范(为目前的开发制定合适的规范) 30 60 ·Design ·具体设计 60 90 ·Coding ·具体编码 600 800 ·CodeReview ·代码复审 60 90 ·Test ·测试(自我测试,修改代码,提交修改) 60 100 Reporting 报告 50 80 ·TestReport ·测试

相关推荐

推荐阅读